@getbourdon/participants 0.2.3 → 0.3.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/LICENSE +1 -1
- package/LICENSE_FAQ.md +1 -1
- package/dist/base.d.ts +109 -0
- package/dist/base.js +88 -0
- package/dist/index.cjs +12 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +42 -1083
- package/dist/index.js +53 -6590
- package/dist/index.js.map +1 -1
- package/dist/network-base.d.ts +108 -0
- package/dist/network-base.js +248 -0
- package/dist/readers/cascade.d.ts +49 -0
- package/dist/readers/cascade.js +428 -0
- package/dist/readers/claude-code-automations.d.ts +62 -0
- package/dist/readers/claude-code-automations.js +693 -0
- package/dist/readers/claude-code.d.ts +50 -0
- package/dist/readers/claude-code.js +590 -0
- package/dist/readers/claude-desktop-code.d.ts +54 -0
- package/dist/readers/claude-desktop-code.js +526 -0
- package/dist/readers/claude-desktop-cowork.d.ts +47 -0
- package/dist/readers/claude-desktop-cowork.js +659 -0
- package/dist/readers/codex-automations.d.ts +55 -0
- package/dist/readers/codex-automations.js +519 -0
- package/dist/readers/codex-sessions.d.ts +88 -0
- package/dist/readers/codex-sessions.js +194 -0
- package/dist/readers/copilot-automations.d.ts +64 -0
- package/dist/readers/copilot-automations.js +530 -0
- package/dist/readers/copilot-cli.d.ts +45 -0
- package/dist/readers/copilot-cli.js +416 -0
- package/dist/readers/copilot-vscode.d.ts +54 -0
- package/dist/readers/copilot-vscode.js +553 -0
- package/dist/readers/copilot.d.ts +59 -0
- package/dist/readers/copilot.js +413 -0
- package/dist/readers/cursor-automations.d.ts +57 -0
- package/dist/readers/cursor-automations.js +685 -0
- package/dist/readers/cursor.d.ts +50 -0
- package/dist/readers/cursor.js +670 -0
- package/dist/readers/github-copilot.d.ts +34 -0
- package/dist/readers/github-copilot.js +242 -0
- package/dist/readers/hermes.d.ts +37 -0
- package/dist/readers/hermes.js +426 -0
- package/dist/readers/openclaw.d.ts +78 -0
- package/dist/readers/openclaw.js +386 -0
- package/dist/registry.d.ts +39 -0
- package/dist/registry.js +98 -0
- package/dist/sqlite-base.d.ts +65 -0
- package/dist/sqlite-base.js +163 -0
- package/package.json +6 -6
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Network-shaped participant base — port of `participants/_network_base.py`
|
|
3
|
+
* (v0.3 adapter contract). Same `exportL5` / `exportSessions` half as a file
|
|
4
|
+
* participant; only the discovery half differs (fetch from an authenticated
|
|
5
|
+
* API). The base provides the three guarantees so adapters don't reimplement:
|
|
6
|
+
*
|
|
7
|
+
* 1. Local TTL cache under `~/.cache/bourdon/<slug>/payload.json` storing ONLY
|
|
8
|
+
* `{fetched_at, payload}` — NEVER the token. A cache hit = zero network.
|
|
9
|
+
* 2. Graceful degradation: network down → serve the most recent cached payload
|
|
10
|
+
* (even expired) and report `degraded` (not silence).
|
|
11
|
+
* 3. Auth boundary: an injected lazy {@link AuthProvider} (env / keychain).
|
|
12
|
+
* An invalid token (401/403 non-ratelimit) ALWAYS propagates as `blocked`
|
|
13
|
+
* and is NEVER masked by stale cache; a missing token serves stale when a
|
|
14
|
+
* cache exists, else blocks; rate-limit degrades.
|
|
15
|
+
*
|
|
16
|
+
* A subclass sets `participantSlug` / `agentId` / `agentType` (+ `nativePath`)
|
|
17
|
+
* and implements `fetchPayload(token)` + `payloadToL5(payload)` (pure, no I/O).
|
|
18
|
+
*/
|
|
19
|
+
import type { L5ManifestModel, SessionModel } from "@getbourdon/l5";
|
|
20
|
+
import { ParticipantError, type AgentStore, type BourdonParticipant, type HealthStatus } from "./base.js";
|
|
21
|
+
export declare const NETWORK_CONTRACT_VERSION = "0.3";
|
|
22
|
+
/** Default cache TTL — adapters override via `cacheTtlSeconds`. */
|
|
23
|
+
export declare const DEFAULT_CACHE_TTL_SECONDS: number;
|
|
24
|
+
/** Transport failure / timeout / 5xx / rate-limit — recoverable via cache fallback. */
|
|
25
|
+
export declare class NetworkUnavailable extends ParticipantError {
|
|
26
|
+
}
|
|
27
|
+
/** 401/403 / missing credential — NOT recoverable via cache. The user must fix
|
|
28
|
+
* auth; surfaced as `blocked`, never silently served from stale cache (stale
|
|
29
|
+
* data would mask a broken token indefinitely). */
|
|
30
|
+
export declare class ParticipantAuthError extends ParticipantError {
|
|
31
|
+
}
|
|
32
|
+
/** A zero-arg callable returning the token string, or null if no credential is
|
|
33
|
+
* available. Kept a callable (not a bare string) so the token is fetched lazily
|
|
34
|
+
* at call time and never sits in the participant's fields or the cache. */
|
|
35
|
+
export type AuthProvider = () => string | null;
|
|
36
|
+
/** Auth provider that reads a token from an environment variable. */
|
|
37
|
+
export declare function envAuthProvider(varName: string): AuthProvider;
|
|
38
|
+
/** `$XDG_CACHE_HOME/bourdon` or `~/.cache/bourdon`. */
|
|
39
|
+
export declare function defaultCacheRoot(): string;
|
|
40
|
+
/** A cached payload + the wall-clock time it was fetched (epoch seconds). */
|
|
41
|
+
export declare class CacheEntry {
|
|
42
|
+
readonly fetchedAt: number;
|
|
43
|
+
readonly payload: Record<string, unknown>;
|
|
44
|
+
constructor(fetchedAt: number, payload: Record<string, unknown>);
|
|
45
|
+
get ageSeconds(): number;
|
|
46
|
+
isFresh(ttlSeconds: number): boolean;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* A tiny JSON file cache, one file per participant slug. Stores only
|
|
50
|
+
* `{fetched_at, payload}` — never the auth token. Read/write are best-effort: a
|
|
51
|
+
* corrupt or unwritable cache degrades to "no cache", never raises.
|
|
52
|
+
*/
|
|
53
|
+
export declare class PayloadCache {
|
|
54
|
+
readonly slug: string;
|
|
55
|
+
readonly root: string;
|
|
56
|
+
readonly path: string;
|
|
57
|
+
constructor(slug: string, rootDir?: string);
|
|
58
|
+
read(): CacheEntry | null;
|
|
59
|
+
write(payload: Record<string, unknown>): void;
|
|
60
|
+
}
|
|
61
|
+
export interface NetworkParticipantOptions {
|
|
62
|
+
authProvider?: AuthProvider | null;
|
|
63
|
+
cacheRoot?: string;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Base for participants whose native state lives behind an authenticated API.
|
|
67
|
+
* Caching, degradation, the auth boundary, and the
|
|
68
|
+
* `discover`/`exportL5`/`exportSessions`/`healthCheck` plumbing live here;
|
|
69
|
+
* subclasses provide only `fetchPayload` + `payloadToL5`.
|
|
70
|
+
*/
|
|
71
|
+
export declare abstract class NetworkParticipant implements BourdonParticipant {
|
|
72
|
+
participantSlug: string;
|
|
73
|
+
agentId: string;
|
|
74
|
+
agentType: string;
|
|
75
|
+
cacheTtlSeconds: number;
|
|
76
|
+
nativePath: string;
|
|
77
|
+
protected readonly authProvider: AuthProvider | null;
|
|
78
|
+
private readonly cacheRoot?;
|
|
79
|
+
private cacheInstance?;
|
|
80
|
+
constructor(opts?: NetworkParticipantOptions);
|
|
81
|
+
/** Lazily built so it reads the SUBCLASS's `participantSlug` — subclass field
|
|
82
|
+
* initializers run after `super()`, so building the cache in the constructor
|
|
83
|
+
* would capture the base "network" slug instead. */
|
|
84
|
+
protected get cache(): PayloadCache;
|
|
85
|
+
/** Do the authenticated API call; return a JSON-serializable dict. Raise
|
|
86
|
+
* {@link NetworkUnavailable} on transport/5xx/rate-limit (→ cache fallback) or
|
|
87
|
+
* {@link ParticipantAuthError} on 401/403 (→ blocked, no fallback). */
|
|
88
|
+
abstract fetchPayload(token: string): Record<string, unknown>;
|
|
89
|
+
/** Normalize a (fresh or cached) payload into an L5 manifest. Pure, no I/O. */
|
|
90
|
+
abstract payloadToL5(payload: Record<string, unknown>): L5ManifestModel;
|
|
91
|
+
/**
|
|
92
|
+
* Resolve (payload, source) where source is 'cache' | 'network' | 'stale-cache'.
|
|
93
|
+
* 1. Fresh cache hit → 'cache' (no network)
|
|
94
|
+
* 2. Miss/expired + token → 'network' (fetch + refresh cache)
|
|
95
|
+
* 3. Net fails + any cache → 'stale-cache' (serve last good payload)
|
|
96
|
+
* 4. Net fails + no cache → raise
|
|
97
|
+
* Auth errors are never swallowed — they propagate so health surfaces
|
|
98
|
+
* 'blocked' rather than serving stale data behind a dead token.
|
|
99
|
+
*/
|
|
100
|
+
protected getPayload(): {
|
|
101
|
+
payload: Record<string, unknown>;
|
|
102
|
+
source: string;
|
|
103
|
+
};
|
|
104
|
+
discover(): AgentStore;
|
|
105
|
+
exportL5(_since?: Date): L5ManifestModel;
|
|
106
|
+
exportSessions(since?: Date, limit?: number): SessionModel[];
|
|
107
|
+
healthCheck(): HealthStatus;
|
|
108
|
+
}
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Network-shaped participant base — port of `participants/_network_base.py`
|
|
3
|
+
* (v0.3 adapter contract). Same `exportL5` / `exportSessions` half as a file
|
|
4
|
+
* participant; only the discovery half differs (fetch from an authenticated
|
|
5
|
+
* API). The base provides the three guarantees so adapters don't reimplement:
|
|
6
|
+
*
|
|
7
|
+
* 1. Local TTL cache under `~/.cache/bourdon/<slug>/payload.json` storing ONLY
|
|
8
|
+
* `{fetched_at, payload}` — NEVER the token. A cache hit = zero network.
|
|
9
|
+
* 2. Graceful degradation: network down → serve the most recent cached payload
|
|
10
|
+
* (even expired) and report `degraded` (not silence).
|
|
11
|
+
* 3. Auth boundary: an injected lazy {@link AuthProvider} (env / keychain).
|
|
12
|
+
* An invalid token (401/403 non-ratelimit) ALWAYS propagates as `blocked`
|
|
13
|
+
* and is NEVER masked by stale cache; a missing token serves stale when a
|
|
14
|
+
* cache exists, else blocks; rate-limit degrades.
|
|
15
|
+
*
|
|
16
|
+
* A subclass sets `participantSlug` / `agentId` / `agentType` (+ `nativePath`)
|
|
17
|
+
* and implements `fetchPayload(token)` + `payloadToL5(payload)` (pure, no I/O).
|
|
18
|
+
*/
|
|
19
|
+
import { mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
20
|
+
import { homedir } from "node:os";
|
|
21
|
+
import { join } from "node:path";
|
|
22
|
+
import { ParticipantError, } from "./base.js";
|
|
23
|
+
export const NETWORK_CONTRACT_VERSION = "0.3";
|
|
24
|
+
/** Default cache TTL — adapters override via `cacheTtlSeconds`. */
|
|
25
|
+
export const DEFAULT_CACHE_TTL_SECONDS = 15 * 60; // 15 minutes
|
|
26
|
+
// -- Network-specific errors --------------------------------------------------
|
|
27
|
+
/** Transport failure / timeout / 5xx / rate-limit — recoverable via cache fallback. */
|
|
28
|
+
export class NetworkUnavailable extends ParticipantError {
|
|
29
|
+
}
|
|
30
|
+
/** 401/403 / missing credential — NOT recoverable via cache. The user must fix
|
|
31
|
+
* auth; surfaced as `blocked`, never silently served from stale cache (stale
|
|
32
|
+
* data would mask a broken token indefinitely). */
|
|
33
|
+
export class ParticipantAuthError extends ParticipantError {
|
|
34
|
+
}
|
|
35
|
+
/** Auth provider that reads a token from an environment variable. */
|
|
36
|
+
export function envAuthProvider(varName) {
|
|
37
|
+
return () => process.env[varName] || null;
|
|
38
|
+
}
|
|
39
|
+
// -- Cache --------------------------------------------------------------------
|
|
40
|
+
/** `$XDG_CACHE_HOME/bourdon` or `~/.cache/bourdon`. */
|
|
41
|
+
export function defaultCacheRoot() {
|
|
42
|
+
const xdg = process.env.XDG_CACHE_HOME;
|
|
43
|
+
const base = xdg ? xdg : join(homedir(), ".cache");
|
|
44
|
+
return join(base, "bourdon");
|
|
45
|
+
}
|
|
46
|
+
/** A cached payload + the wall-clock time it was fetched (epoch seconds). */
|
|
47
|
+
export class CacheEntry {
|
|
48
|
+
fetchedAt;
|
|
49
|
+
payload;
|
|
50
|
+
constructor(fetchedAt, payload) {
|
|
51
|
+
this.fetchedAt = fetchedAt;
|
|
52
|
+
this.payload = payload;
|
|
53
|
+
}
|
|
54
|
+
get ageSeconds() {
|
|
55
|
+
return Math.max(0, Date.now() / 1000 - this.fetchedAt);
|
|
56
|
+
}
|
|
57
|
+
isFresh(ttlSeconds) {
|
|
58
|
+
return this.ageSeconds < ttlSeconds;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* A tiny JSON file cache, one file per participant slug. Stores only
|
|
63
|
+
* `{fetched_at, payload}` — never the auth token. Read/write are best-effort: a
|
|
64
|
+
* corrupt or unwritable cache degrades to "no cache", never raises.
|
|
65
|
+
*/
|
|
66
|
+
export class PayloadCache {
|
|
67
|
+
slug;
|
|
68
|
+
root;
|
|
69
|
+
path;
|
|
70
|
+
constructor(slug, rootDir) {
|
|
71
|
+
this.slug = slug;
|
|
72
|
+
this.root = join(rootDir ?? defaultCacheRoot(), slug);
|
|
73
|
+
this.path = join(this.root, "payload.json");
|
|
74
|
+
}
|
|
75
|
+
read() {
|
|
76
|
+
let raw;
|
|
77
|
+
try {
|
|
78
|
+
raw = JSON.parse(readFileSync(this.path, "utf8"));
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
if (typeof raw !== "object" || raw === null || !("payload" in raw))
|
|
84
|
+
return null;
|
|
85
|
+
const obj = raw;
|
|
86
|
+
let fetchedAt = Number(obj["fetched_at"] ?? 0);
|
|
87
|
+
if (!Number.isFinite(fetchedAt))
|
|
88
|
+
fetchedAt = 0;
|
|
89
|
+
const payload = obj["payload"];
|
|
90
|
+
if (typeof payload !== "object" || payload === null || Array.isArray(payload))
|
|
91
|
+
return null;
|
|
92
|
+
return new CacheEntry(fetchedAt, payload);
|
|
93
|
+
}
|
|
94
|
+
write(payload) {
|
|
95
|
+
try {
|
|
96
|
+
mkdirSync(this.root, { recursive: true });
|
|
97
|
+
const tmp = `${this.path}.tmp`;
|
|
98
|
+
writeFileSync(tmp, JSON.stringify({ fetched_at: Date.now() / 1000, payload }), "utf8");
|
|
99
|
+
renameSync(tmp, this.path); // atomic
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
/* best-effort; a write failure degrades to "no cache" */
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// -- Base participant ---------------------------------------------------------
|
|
107
|
+
/**
|
|
108
|
+
* Base for participants whose native state lives behind an authenticated API.
|
|
109
|
+
* Caching, degradation, the auth boundary, and the
|
|
110
|
+
* `discover`/`exportL5`/`exportSessions`/`healthCheck` plumbing live here;
|
|
111
|
+
* subclasses provide only `fetchPayload` + `payloadToL5`.
|
|
112
|
+
*/
|
|
113
|
+
export class NetworkParticipant {
|
|
114
|
+
participantSlug = "network";
|
|
115
|
+
agentId = "network";
|
|
116
|
+
agentType = "other";
|
|
117
|
+
cacheTtlSeconds = DEFAULT_CACHE_TTL_SECONDS;
|
|
118
|
+
nativePath = "network://";
|
|
119
|
+
authProvider;
|
|
120
|
+
cacheRoot;
|
|
121
|
+
cacheInstance;
|
|
122
|
+
constructor(opts = {}) {
|
|
123
|
+
this.authProvider = opts.authProvider ?? null;
|
|
124
|
+
this.cacheRoot = opts.cacheRoot;
|
|
125
|
+
}
|
|
126
|
+
/** Lazily built so it reads the SUBCLASS's `participantSlug` — subclass field
|
|
127
|
+
* initializers run after `super()`, so building the cache in the constructor
|
|
128
|
+
* would capture the base "network" slug instead. */
|
|
129
|
+
get cache() {
|
|
130
|
+
if (!this.cacheInstance) {
|
|
131
|
+
this.cacheInstance = new PayloadCache(this.participantSlug, this.cacheRoot);
|
|
132
|
+
}
|
|
133
|
+
return this.cacheInstance;
|
|
134
|
+
}
|
|
135
|
+
// -- Core fetch-with-cache-and-degrade -------------------------------------
|
|
136
|
+
/**
|
|
137
|
+
* Resolve (payload, source) where source is 'cache' | 'network' | 'stale-cache'.
|
|
138
|
+
* 1. Fresh cache hit → 'cache' (no network)
|
|
139
|
+
* 2. Miss/expired + token → 'network' (fetch + refresh cache)
|
|
140
|
+
* 3. Net fails + any cache → 'stale-cache' (serve last good payload)
|
|
141
|
+
* 4. Net fails + no cache → raise
|
|
142
|
+
* Auth errors are never swallowed — they propagate so health surfaces
|
|
143
|
+
* 'blocked' rather than serving stale data behind a dead token.
|
|
144
|
+
*/
|
|
145
|
+
getPayload() {
|
|
146
|
+
const cached = this.cache.read();
|
|
147
|
+
if (cached !== null && cached.isFresh(this.cacheTtlSeconds)) {
|
|
148
|
+
return { payload: cached.payload, source: "cache" };
|
|
149
|
+
}
|
|
150
|
+
const token = this.authProvider ? this.authProvider() : null;
|
|
151
|
+
if (!token) {
|
|
152
|
+
// No credential: if we have any cache, serve it stale; else blocked.
|
|
153
|
+
if (cached !== null)
|
|
154
|
+
return { payload: cached.payload, source: "stale-cache" };
|
|
155
|
+
throw new ParticipantAuthError(`${this.participantSlug}: no auth token available and no cache`);
|
|
156
|
+
}
|
|
157
|
+
let payload;
|
|
158
|
+
try {
|
|
159
|
+
payload = this.fetchPayload(token);
|
|
160
|
+
}
|
|
161
|
+
catch (err) {
|
|
162
|
+
if (err instanceof ParticipantAuthError)
|
|
163
|
+
throw err; // never mask a bad token
|
|
164
|
+
if (err instanceof NetworkUnavailable) {
|
|
165
|
+
if (cached !== null)
|
|
166
|
+
return { payload: cached.payload, source: "stale-cache" };
|
|
167
|
+
throw err;
|
|
168
|
+
}
|
|
169
|
+
throw err;
|
|
170
|
+
}
|
|
171
|
+
this.cache.write(payload);
|
|
172
|
+
return { payload, source: "network" };
|
|
173
|
+
}
|
|
174
|
+
// -- Participant protocol ---------------------------------------------------
|
|
175
|
+
discover() {
|
|
176
|
+
const { source } = this.getPayload();
|
|
177
|
+
return {
|
|
178
|
+
path: this.nativePath,
|
|
179
|
+
version: `${this.participantSlug}-network-v1`,
|
|
180
|
+
metadata: { source, contract_version: NETWORK_CONTRACT_VERSION },
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
exportL5(_since) {
|
|
184
|
+
const { payload } = this.getPayload();
|
|
185
|
+
return this.payloadToL5(payload);
|
|
186
|
+
}
|
|
187
|
+
exportSessions(since, limit = 100) {
|
|
188
|
+
const manifest = this.exportL5(since);
|
|
189
|
+
let sessions = manifest.recent_sessions ?? [];
|
|
190
|
+
if (since) {
|
|
191
|
+
const cutoff = since.toISOString().slice(0, 10);
|
|
192
|
+
sessions = sessions.filter((s) => (s.date || "") >= cutoff);
|
|
193
|
+
}
|
|
194
|
+
return sessions.slice(0, limit);
|
|
195
|
+
}
|
|
196
|
+
healthCheck() {
|
|
197
|
+
let source;
|
|
198
|
+
try {
|
|
199
|
+
source = this.getPayload().source;
|
|
200
|
+
}
|
|
201
|
+
catch (err) {
|
|
202
|
+
if (err instanceof ParticipantAuthError) {
|
|
203
|
+
return {
|
|
204
|
+
status: "blocked",
|
|
205
|
+
reason: String(err.message),
|
|
206
|
+
details: { participant: this.participantSlug },
|
|
207
|
+
proposedFix: `Provide a valid credential for ${this.participantSlug} ` +
|
|
208
|
+
"(see the adapter docs for the auth path) and re-run `bourdon export-all`.",
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
if (err instanceof NetworkUnavailable) {
|
|
212
|
+
return {
|
|
213
|
+
status: "degraded",
|
|
214
|
+
reason: `network unavailable and no cache: ${err.message}`,
|
|
215
|
+
details: { participant: this.participantSlug },
|
|
216
|
+
proposedFix: "Check connectivity, then re-run `bourdon export-all`.",
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
// Defense in depth: health_check must NEVER raise. An adapter's
|
|
220
|
+
// fetchPayload should only raise the two contract errors; anything else is
|
|
221
|
+
// reported as blocked rather than propagated.
|
|
222
|
+
return {
|
|
223
|
+
status: "blocked",
|
|
224
|
+
reason: `unexpected error resolving payload: ${String(err)}`,
|
|
225
|
+
details: { participant: this.participantSlug },
|
|
226
|
+
proposedFix: `${this.participantSlug} raised an unexpected error during healthCheck; ` +
|
|
227
|
+
"its fetchPayload should only raise ParticipantAuthError / NetworkUnavailable.",
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
const cached = this.cache.read();
|
|
231
|
+
const details = { participant: this.participantSlug, source };
|
|
232
|
+
if (cached !== null) {
|
|
233
|
+
details["cache_age_seconds"] = Math.round(cached.ageSeconds * 10) / 10;
|
|
234
|
+
details["cache_fetched_at"] = new Date(cached.fetchedAt * 1000)
|
|
235
|
+
.toISOString()
|
|
236
|
+
.replace(/\.\d{3}Z$/, "+00:00");
|
|
237
|
+
}
|
|
238
|
+
if (source === "stale-cache") {
|
|
239
|
+
return {
|
|
240
|
+
status: "degraded",
|
|
241
|
+
reason: "serving stale cache (network unavailable or no token)",
|
|
242
|
+
details,
|
|
243
|
+
proposedFix: "Restore connectivity / refresh the token to update.",
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
return { status: "ok", details };
|
|
247
|
+
}
|
|
248
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cascade (Windsurf) participant — convention-file reader. Port of
|
|
3
|
+
* `participants/cascade.py`.
|
|
4
|
+
*
|
|
5
|
+
* Cascade's internal state is not exposed on the filesystem in a standardized
|
|
6
|
+
* format (like cloud Copilot). Instead this participant uses a CONVENTION FILE:
|
|
7
|
+
* Cascade maintains a structured memory file at `~/.cascade-bourdon/memory.md`
|
|
8
|
+
* with YAML front-matter carrying `entities` + `sessions`. Cascade owns that
|
|
9
|
+
* projection explicitly (it writes what it knows at session end); the
|
|
10
|
+
* participant normalizes the front-matter into an L5 manifest for federation.
|
|
11
|
+
*
|
|
12
|
+
* Privacy: entity/session summaries pass through the redaction SSOT; the
|
|
13
|
+
* visibility policy (private_tags) filters PRIVATE entities before emission.
|
|
14
|
+
*/
|
|
15
|
+
import { type L5ManifestModel, type SessionModel, type VisibilityPolicyModel } from "@getbourdon/l5";
|
|
16
|
+
import { type AgentStore, type BourdonParticipant, type HealthStatus } from "../base.js";
|
|
17
|
+
/** Return the default Cascade-Bourdon convention directory (`~/.cascade-bourdon`). */
|
|
18
|
+
export declare function defaultCascadeDir(): string;
|
|
19
|
+
/** Return the default path to the Cascade memory file. */
|
|
20
|
+
export declare function defaultCascadeMemoryPath(): string;
|
|
21
|
+
/**
|
|
22
|
+
* Create a starter memory.md in the Cascade-Bourdon convention directory.
|
|
23
|
+
*
|
|
24
|
+
* @param cascadeDir Override the convention directory (default `~/.cascade-bourdon`).
|
|
25
|
+
* @param force Overwrite an existing file; otherwise throws.
|
|
26
|
+
* @returns the path to the created memory file.
|
|
27
|
+
*/
|
|
28
|
+
export declare function initMemoryFile(cascadeDir?: string, force?: boolean): string;
|
|
29
|
+
/**
|
|
30
|
+
* Convention-based Bourdon participant for Cascade (Windsurf). Reads structured
|
|
31
|
+
* memory from `~/.cascade-bourdon/memory.md` and normalizes it into L5.
|
|
32
|
+
*/
|
|
33
|
+
export declare class CascadeParticipant implements BourdonParticipant {
|
|
34
|
+
agentId: string;
|
|
35
|
+
agentType: string;
|
|
36
|
+
displayName: string;
|
|
37
|
+
private readonly dir;
|
|
38
|
+
private readonly policy;
|
|
39
|
+
static defaultNativePath(home?: string): string;
|
|
40
|
+
constructor(cascadeDir?: string, policy?: VisibilityPolicyModel);
|
|
41
|
+
/** Path to the Cascade-Bourdon convention directory. */
|
|
42
|
+
get nativePath(): string;
|
|
43
|
+
private memoryPath;
|
|
44
|
+
private readFrontmatter;
|
|
45
|
+
discover(): AgentStore;
|
|
46
|
+
exportL5(since?: Date): L5ManifestModel;
|
|
47
|
+
exportSessions(since?: Date, limit?: number): SessionModel[];
|
|
48
|
+
healthCheck(): HealthStatus;
|
|
49
|
+
}
|