@getbourdon/participants 0.5.6 → 0.6.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.
- package/dist/index.cjs +3595 -772
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +954 -5
- package/dist/index.d.ts +6 -1
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -1
- package/dist/readers/claude-code.d.ts +21 -2
- package/dist/readers/claude-code.js +31 -1
- package/dist/readers/cursor.d.ts +23 -2
- package/dist/readers/cursor.js +33 -1
- package/dist/skill-index.d.ts +110 -0
- package/dist/skill-index.js +470 -0
- package/dist/skill-proposals.d.ts +212 -0
- package/dist/skill-proposals.js +757 -0
- package/dist/skill-shares.d.ts +128 -0
- package/dist/skill-shares.js +366 -0
- package/dist/skill-store.d.ts +186 -0
- package/dist/skill-store.js +750 -0
- package/dist/skills.d.ts +295 -0
- package/dist/skills.js +999 -0
- package/package.json +5 -4
|
@@ -15,8 +15,9 @@
|
|
|
15
15
|
* federation. Entities are deduped by case-insensitive name and sorted
|
|
16
16
|
* alphabetically.
|
|
17
17
|
*/
|
|
18
|
-
import { type L5ManifestModel, type SessionModel } from "@getbourdon/l5";
|
|
18
|
+
import { type L5ManifestModel, type SessionModel, type SkillRefModel } from "@getbourdon/l5";
|
|
19
19
|
import { type AgentStore, type BourdonParticipant, type HealthStatus } from "../base.js";
|
|
20
|
+
import { type SkillScanReport, type SkillSource } from "../skills.js";
|
|
20
21
|
/** Directory names for the knowledge repo. Only these are scanned. */
|
|
21
22
|
export declare const BRAIN_DIR_NAMES: readonly [string];
|
|
22
23
|
/** Env override pointing at the knowledge repo explicitly. */
|
|
@@ -32,7 +33,25 @@ export declare class ClaudeCodeParticipant implements BourdonParticipant {
|
|
|
32
33
|
autoMemoryPath: string | null;
|
|
33
34
|
knowledgeGraphPath: string | null;
|
|
34
35
|
static defaultNativePath(home?: string): string;
|
|
35
|
-
|
|
36
|
+
/**
|
|
37
|
+
* Explicit skill directories; `null` = the defaults (see skills.ts), read
|
|
38
|
+
* only for shared skills unless `BOURDON_SKILLS_ADVERTISE` lists all.
|
|
39
|
+
* Explicit sources list every skill in them.
|
|
40
|
+
*/
|
|
41
|
+
private readonly explicitSkillSources;
|
|
42
|
+
constructor(options?: {
|
|
43
|
+
skillSources?: readonly SkillSource[] | null;
|
|
44
|
+
});
|
|
45
|
+
/**
|
|
46
|
+
* `~/.claude/skills` (or the config-dir override) and the cross-agent store,
|
|
47
|
+
* plus the opted-in projects' `.claude/skills` and `.agents/skills`.
|
|
48
|
+
*/
|
|
49
|
+
/** Built with explicit skill sources: this participant lists all of them. */
|
|
50
|
+
hasExplicitSkillSources(): boolean;
|
|
51
|
+
skillSources(): SkillSource[];
|
|
52
|
+
/** Advertised skills plus the skills that could not be advertised. */
|
|
53
|
+
scanSkills(): SkillScanReport;
|
|
54
|
+
exportSkills(): SkillRefModel[];
|
|
36
55
|
discover(): AgentStore;
|
|
37
56
|
exportL5(since?: Date): L5ManifestModel;
|
|
38
57
|
exportSessions(since?: Date, limit?: number): SessionModel[];
|
|
@@ -23,6 +23,7 @@ import { parse as yamlParse } from "yaml";
|
|
|
23
23
|
import { Visibility, filterForFederation, makeAgentInfo, makeEntity, makeManifest, makeSession, makeVisibilityPolicy, } from "@getbourdon/l5";
|
|
24
24
|
import { containsSecret } from "@getbourdon/redaction";
|
|
25
25
|
import { ParticipantDiscoveryError, SPEC_VERSION, } from "../base.js";
|
|
26
|
+
import { advertisedSkills, claudeCodeSkillSources, crossAgentSkillSources, scanSkillSources, } from "../skills.js";
|
|
26
27
|
const AGENT_ID = "claude-code";
|
|
27
28
|
const AGENT_TYPE = "code-assistant";
|
|
28
29
|
const ROLE_NARRATIVE = "Agentic manager and code-assistant. Coordinates the agent fleet, " +
|
|
@@ -478,11 +479,39 @@ export class ClaudeCodeParticipant {
|
|
|
478
479
|
static defaultNativePath(home) {
|
|
479
480
|
return join(home ?? homeDir(), ".claude");
|
|
480
481
|
}
|
|
481
|
-
|
|
482
|
+
/**
|
|
483
|
+
* Explicit skill directories; `null` = the defaults (see skills.ts), read
|
|
484
|
+
* only for shared skills unless `BOURDON_SKILLS_ADVERTISE` lists all.
|
|
485
|
+
* Explicit sources list every skill in them.
|
|
486
|
+
*/
|
|
487
|
+
explicitSkillSources;
|
|
488
|
+
constructor(options = {}) {
|
|
482
489
|
this.nativePath = join(homeDir(), BRAIN_DIR_NAMES[0]); // primary anchor
|
|
483
490
|
this.brainPath = resolveBrainPath();
|
|
484
491
|
this.autoMemoryPath = resolveAutoMemoryPath();
|
|
485
492
|
this.knowledgeGraphPath = resolveKnowledgeGraphPath();
|
|
493
|
+
this.explicitSkillSources = options.skillSources == null ? null : [...options.skillSources];
|
|
494
|
+
}
|
|
495
|
+
// -- Skills (plan 005: discovery only) -----------------------------------------
|
|
496
|
+
/**
|
|
497
|
+
* `~/.claude/skills` (or the config-dir override) and the cross-agent store,
|
|
498
|
+
* plus the opted-in projects' `.claude/skills` and `.agents/skills`.
|
|
499
|
+
*/
|
|
500
|
+
/** Built with explicit skill sources: this participant lists all of them. */
|
|
501
|
+
hasExplicitSkillSources() {
|
|
502
|
+
return this.explicitSkillSources !== null;
|
|
503
|
+
}
|
|
504
|
+
skillSources() {
|
|
505
|
+
if (this.explicitSkillSources !== null)
|
|
506
|
+
return [...this.explicitSkillSources];
|
|
507
|
+
return [...claudeCodeSkillSources(), ...crossAgentSkillSources()];
|
|
508
|
+
}
|
|
509
|
+
/** Advertised skills plus the skills that could not be advertised. */
|
|
510
|
+
scanSkills() {
|
|
511
|
+
return scanSkillSources(this.skillSources());
|
|
512
|
+
}
|
|
513
|
+
exportSkills() {
|
|
514
|
+
return this.scanSkills().refs;
|
|
486
515
|
}
|
|
487
516
|
discover() {
|
|
488
517
|
const sources = {
|
|
@@ -531,6 +560,7 @@ export class ClaudeCodeParticipant {
|
|
|
531
560
|
recent_sessions: sessions,
|
|
532
561
|
known_entities: visibleEntities,
|
|
533
562
|
visibility_policy: DEFAULT_POLICY,
|
|
563
|
+
skills: advertisedSkills(this),
|
|
534
564
|
});
|
|
535
565
|
}
|
|
536
566
|
exportSessions(since, limit = 100) {
|
package/dist/readers/cursor.d.ts
CHANGED
|
@@ -18,8 +18,9 @@
|
|
|
18
18
|
* deterministic, visibility-enforced-before-emission, redaction on every native
|
|
19
19
|
* string; `healthCheck` never throws.
|
|
20
20
|
*/
|
|
21
|
-
import { type L5ManifestModel, type SessionModel } from "@getbourdon/l5";
|
|
21
|
+
import { type L5ManifestModel, type SessionModel, type SkillRefModel } from "@getbourdon/l5";
|
|
22
22
|
import { type AgentStore, type BourdonParticipant, type HealthStatus } from "../base.js";
|
|
23
|
+
import { type SkillScanReport, type SkillSource } from "../skills.js";
|
|
23
24
|
/**
|
|
24
25
|
* Platform-specific Cursor data dir (the SQLite workspace state lives here),
|
|
25
26
|
* `$CURSOR_DIR` override first. Returns null on an unrecognized platform (or
|
|
@@ -40,7 +41,27 @@ export declare class CursorParticipant implements BourdonParticipant {
|
|
|
40
41
|
* extraction intentionally use different anchors.
|
|
41
42
|
*/
|
|
42
43
|
static defaultNativePath(home?: string): string;
|
|
43
|
-
|
|
44
|
+
/**
|
|
45
|
+
* Explicit skill directories; `null` = the defaults (see skills.ts), read
|
|
46
|
+
* only for shared skills unless `BOURDON_SKILLS_ADVERTISE` lists all.
|
|
47
|
+
* Explicit sources list every skill in them.
|
|
48
|
+
* `workspaceRoot` does not opt a project in: that takes an explicit
|
|
49
|
+
* `BOURDON_SKILL_PROJECTS` entry, or explicit sources.
|
|
50
|
+
*/
|
|
51
|
+
private readonly explicitSkillSources;
|
|
52
|
+
constructor(cursorDir?: string | null, workspaceRoot?: string | null, options?: {
|
|
53
|
+
skillSources?: readonly SkillSource[] | null;
|
|
54
|
+
});
|
|
55
|
+
/**
|
|
56
|
+
* `~/.cursor/skills` (not the built-in `skills-cursor`) and the cross-agent
|
|
57
|
+
* store, plus the opted-in projects' `.cursor/skills` and `.agents/skills`.
|
|
58
|
+
*/
|
|
59
|
+
/** Built with explicit skill sources: this participant lists all of them. */
|
|
60
|
+
hasExplicitSkillSources(): boolean;
|
|
61
|
+
skillSources(): SkillSource[];
|
|
62
|
+
/** Advertised skills plus the skills that could not be advertised. */
|
|
63
|
+
scanSkills(): SkillScanReport;
|
|
64
|
+
exportSkills(): SkillRefModel[];
|
|
44
65
|
get nativePath(): string;
|
|
45
66
|
discover(): AgentStore;
|
|
46
67
|
exportSessions(since?: Date, limit?: number): SessionModel[];
|
package/dist/readers/cursor.js
CHANGED
|
@@ -25,6 +25,7 @@ import { basename, join } from "node:path";
|
|
|
25
25
|
import { Visibility, filterForFederation, makeAgentInfo, makeEntity, makeManifest, makeSession, makeVisibilityPolicy, } from "@getbourdon/l5";
|
|
26
26
|
import { redactText } from "@getbourdon/redaction";
|
|
27
27
|
import { ParticipantDiscoveryError, SPEC_VERSION, } from "../base.js";
|
|
28
|
+
import { advertisedSkills, crossAgentSkillSources, cursorSkillSources, scanSkillSources, } from "../skills.js";
|
|
28
29
|
import { tableExists, tryOpenReadonly } from "../sqlite-base.js";
|
|
29
30
|
const AGENT_ID = "cursor";
|
|
30
31
|
const AGENT_TYPE = "code-assistant";
|
|
@@ -529,9 +530,39 @@ export class CursorParticipant {
|
|
|
529
530
|
static defaultNativePath(home) {
|
|
530
531
|
return join(home ?? homeDir(), ".cursor");
|
|
531
532
|
}
|
|
532
|
-
|
|
533
|
+
/**
|
|
534
|
+
* Explicit skill directories; `null` = the defaults (see skills.ts), read
|
|
535
|
+
* only for shared skills unless `BOURDON_SKILLS_ADVERTISE` lists all.
|
|
536
|
+
* Explicit sources list every skill in them.
|
|
537
|
+
* `workspaceRoot` does not opt a project in: that takes an explicit
|
|
538
|
+
* `BOURDON_SKILL_PROJECTS` entry, or explicit sources.
|
|
539
|
+
*/
|
|
540
|
+
explicitSkillSources;
|
|
541
|
+
constructor(cursorDir, workspaceRoot, options = {}) {
|
|
533
542
|
this.cursorDir = cursorDir ?? null;
|
|
534
543
|
this.workspaceRoot = workspaceRoot ?? null;
|
|
544
|
+
this.explicitSkillSources = options.skillSources == null ? null : [...options.skillSources];
|
|
545
|
+
}
|
|
546
|
+
// -- Skills (plan 005: discovery only) -----------------------------------------
|
|
547
|
+
/**
|
|
548
|
+
* `~/.cursor/skills` (not the built-in `skills-cursor`) and the cross-agent
|
|
549
|
+
* store, plus the opted-in projects' `.cursor/skills` and `.agents/skills`.
|
|
550
|
+
*/
|
|
551
|
+
/** Built with explicit skill sources: this participant lists all of them. */
|
|
552
|
+
hasExplicitSkillSources() {
|
|
553
|
+
return this.explicitSkillSources !== null;
|
|
554
|
+
}
|
|
555
|
+
skillSources() {
|
|
556
|
+
if (this.explicitSkillSources !== null)
|
|
557
|
+
return [...this.explicitSkillSources];
|
|
558
|
+
return [...cursorSkillSources(), ...crossAgentSkillSources()];
|
|
559
|
+
}
|
|
560
|
+
/** Advertised skills plus the skills that could not be advertised. */
|
|
561
|
+
scanSkills() {
|
|
562
|
+
return scanSkillSources(this.skillSources());
|
|
563
|
+
}
|
|
564
|
+
exportSkills() {
|
|
565
|
+
return this.scanSkills().refs;
|
|
535
566
|
}
|
|
536
567
|
get nativePath() {
|
|
537
568
|
const path = this.cursorDir ?? defaultCursorDir();
|
|
@@ -609,6 +640,7 @@ export class CursorParticipant {
|
|
|
609
640
|
recent_sessions: sessions,
|
|
610
641
|
known_entities: visibleEntities,
|
|
611
642
|
visibility_policy: this.policy,
|
|
643
|
+
skills: advertisedSkills(this),
|
|
612
644
|
});
|
|
613
645
|
}
|
|
614
646
|
healthCheck() {
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reader-side skill folder scan (plan 005). Port of the parts of the engine's
|
|
3
|
+
* `core/skill_index.py` a participant needs to advertise a local skill: the
|
|
4
|
+
* text-only content rules, the no-follow folder walk, front-matter parsing,
|
|
5
|
+
* the `content_sha256` framing and `scan_local_skill` (skip and flag).
|
|
6
|
+
*
|
|
7
|
+
* `readSkillFolder` is the promotion-side twin of `scanLocalSkill`: it refuses
|
|
8
|
+
* a folder that breaks any rule instead of skipping files. The library-level
|
|
9
|
+
* shared store (index rows, versions, promotion) is in `skill-store.ts`. Both
|
|
10
|
+
* use the same limits and name rule, so a hash computed here compares
|
|
11
|
+
* directly with a shared skill's.
|
|
12
|
+
*
|
|
13
|
+
* Rules a v1 shared skill must meet (anything else is skipped and flagged):
|
|
14
|
+
* - `SKILL.md` plus markdown, plain text and template files only;
|
|
15
|
+
* - no links, no hidden entries, bounded depth and path length, no paths that
|
|
16
|
+
* differ only in case;
|
|
17
|
+
* - UTF-8 text without NUL bytes, no interpreter line, no credential-like text;
|
|
18
|
+
* - per-file and total size caps, at most {@link MAX_REFERENCE_FILES} reference files.
|
|
19
|
+
*/
|
|
20
|
+
import { type Stats } from "node:fs";
|
|
21
|
+
export declare const SKILL_BODY_NAME = "SKILL.md";
|
|
22
|
+
/** Reference-file types a v1 shared skill may carry: markdown, plain text and templates. */
|
|
23
|
+
export declare const TEXT_FILE_SUFFIXES: ReadonlySet<string>;
|
|
24
|
+
export declare const MAX_SKILL_BODY_BYTES: number;
|
|
25
|
+
export declare const MAX_REFERENCE_FILE_BYTES: number;
|
|
26
|
+
export declare const MAX_REFERENCE_FILES = 64;
|
|
27
|
+
export declare const MAX_SKILL_TOTAL_BYTES: number;
|
|
28
|
+
/**
|
|
29
|
+
* Why a reader left a file out of an advertised skill. `limit` means the
|
|
30
|
+
* file-count or total-size cap was reached; every other code names the content
|
|
31
|
+
* rule the file breaks.
|
|
32
|
+
*/
|
|
33
|
+
export declare const SKIP_REASONS: ReadonlySet<string>;
|
|
34
|
+
/** Longest skill name, in code points. */
|
|
35
|
+
export declare const SKILL_NAME_MAX: number;
|
|
36
|
+
/** Longest front-matter description, in code points. */
|
|
37
|
+
export declare const SKILL_DESCRIPTION_MAX: number;
|
|
38
|
+
/**
|
|
39
|
+
* A skill folder cannot be advertised (or shared) as it stands. `problems`
|
|
40
|
+
* lists every offending path with the reason; content is never echoed back.
|
|
41
|
+
*/
|
|
42
|
+
export declare class SkillContentError extends Error {
|
|
43
|
+
readonly problems: string[];
|
|
44
|
+
constructor(problems: string[]);
|
|
45
|
+
}
|
|
46
|
+
/** Python `str.strip()` with no argument. */
|
|
47
|
+
export declare function pyStrip(text: string): string;
|
|
48
|
+
/** Length in code points, as Python's `len(str)`. */
|
|
49
|
+
export declare function codePointLength(text: string): number;
|
|
50
|
+
/** The first `limit` code points, as Python's `text[:limit]`. */
|
|
51
|
+
export declare function codePointSlice(text: string, limit: number): string;
|
|
52
|
+
/** Code-point order (Python's str order), via the UTF-8 bytes. */
|
|
53
|
+
export declare function compareUtf8(a: string, b: string): number;
|
|
54
|
+
/** Whether `path` is a symbolic link (on Windows, a junction or symlink reparse point). */
|
|
55
|
+
export declare function isPathLinkOrReparse(path: string, stats?: Stats): boolean;
|
|
56
|
+
export interface SkillFrontMatter {
|
|
57
|
+
name: string;
|
|
58
|
+
description: string;
|
|
59
|
+
}
|
|
60
|
+
/** Why `value` is not a valid skill name (`label` names the field), or null. */
|
|
61
|
+
export declare function skillNameError(value: unknown, label?: string): string | null;
|
|
62
|
+
/** Extract `name` and `description` from a `SKILL.md` body. Throws {@link SkillContentError}. */
|
|
63
|
+
export declare function parseFrontMatter(body: Uint8Array | string): SkillFrontMatter;
|
|
64
|
+
/**
|
|
65
|
+
* Hash a skill's files as the schema's `content_sha256` defines: entries sorted
|
|
66
|
+
* by the UTF-8 bytes of their POSIX path relative to the skill folder, each
|
|
67
|
+
* framed as `path \0 len(bytes) \0 bytes`.
|
|
68
|
+
*/
|
|
69
|
+
export declare function computeContentSha256(entries: Iterable<readonly [string, Uint8Array]>): string;
|
|
70
|
+
/** One file a reader left out of a local skill, and why (a {@link SKIP_REASONS} code). */
|
|
71
|
+
export interface SkippedFile {
|
|
72
|
+
path: string;
|
|
73
|
+
reason: string;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* What a participant reader can advertise about one local skill folder. `files`
|
|
77
|
+
* is the shareable part (`SKILL.md` plus every reference file that passes the
|
|
78
|
+
* v1 content rules); `skipped` lists the rest. The hash covers `files` only.
|
|
79
|
+
*/
|
|
80
|
+
export interface LocalSkillScan {
|
|
81
|
+
frontMatter: SkillFrontMatter;
|
|
82
|
+
files: ReadonlyArray<readonly [string, Uint8Array]>;
|
|
83
|
+
skipped: readonly SkippedFile[];
|
|
84
|
+
contentSha256: string;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Scan one local skill folder for discovery: skip and flag, don't refuse.
|
|
88
|
+
*
|
|
89
|
+
* A disallowed reference file (a script, a binary, a link, a hidden file,
|
|
90
|
+
* credential-like text) is left out and reported in `skipped` instead of making
|
|
91
|
+
* the whole skill disappear. Only a `SKILL.md` that is missing, unreadable or
|
|
92
|
+
* itself breaks a content rule throws {@link SkillContentError}, because then
|
|
93
|
+
* there is nothing safe to advertise. Nothing is followed through a link and
|
|
94
|
+
* nothing is modified.
|
|
95
|
+
*/
|
|
96
|
+
export declare function scanLocalSkill(folder: string): LocalSkillScan;
|
|
97
|
+
/** A validated skill: front matter plus every file, `SKILL.md` included, sorted by path. */
|
|
98
|
+
export interface SkillContent {
|
|
99
|
+
frontMatter: SkillFrontMatter;
|
|
100
|
+
files: ReadonlyArray<readonly [string, Uint8Array]>;
|
|
101
|
+
}
|
|
102
|
+
/** The `SKILL.md` bytes of `content`. */
|
|
103
|
+
export declare function skillContentBody(content: SkillContent): Uint8Array;
|
|
104
|
+
/**
|
|
105
|
+
* Read a skill folder and enforce every v1 content rule (the oracle's
|
|
106
|
+
* `read_skill_folder`). Throws {@link SkillContentError} listing every problem
|
|
107
|
+
* found. The folder is read in place and never modified; links are reported,
|
|
108
|
+
* never followed.
|
|
109
|
+
*/
|
|
110
|
+
export declare function readSkillFolder(folder: string): SkillContent;
|