@braidhq/server 0.0.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.
- package/LICENSE +21 -0
- package/dist/app.d.ts +7 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +71 -0
- package/dist/app.js.map +1 -0
- package/dist/composeFs.d.ts +20 -0
- package/dist/composeFs.d.ts.map +1 -0
- package/dist/composeFs.js +134 -0
- package/dist/composeFs.js.map +1 -0
- package/dist/composition.d.ts +49 -0
- package/dist/composition.d.ts.map +1 -0
- package/dist/composition.js +43 -0
- package/dist/composition.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/infrastructure/agent/ClaudeCodeAgentBinding.d.ts +8 -0
- package/dist/infrastructure/agent/ClaudeCodeAgentBinding.d.ts.map +1 -0
- package/dist/infrastructure/agent/ClaudeCodeAgentBinding.js +62 -0
- package/dist/infrastructure/agent/ClaudeCodeAgentBinding.js.map +1 -0
- package/dist/infrastructure/agent/SubprocessSkillRunner.d.ts +54 -0
- package/dist/infrastructure/agent/SubprocessSkillRunner.d.ts.map +1 -0
- package/dist/infrastructure/agent/SubprocessSkillRunner.js +240 -0
- package/dist/infrastructure/agent/SubprocessSkillRunner.js.map +1 -0
- package/dist/infrastructure/agent/asyncQueue.d.ts +22 -0
- package/dist/infrastructure/agent/asyncQueue.d.ts.map +1 -0
- package/dist/infrastructure/agent/asyncQueue.js +43 -0
- package/dist/infrastructure/agent/asyncQueue.js.map +1 -0
- package/dist/infrastructure/agent/mcpConfig.d.ts +18 -0
- package/dist/infrastructure/agent/mcpConfig.d.ts.map +1 -0
- package/dist/infrastructure/agent/mcpConfig.js +47 -0
- package/dist/infrastructure/agent/mcpConfig.js.map +1 -0
- package/dist/infrastructure/agent/streamJsonParser.d.ts +20 -0
- package/dist/infrastructure/agent/streamJsonParser.d.ts.map +1 -0
- package/dist/infrastructure/agent/streamJsonParser.js +44 -0
- package/dist/infrastructure/agent/streamJsonParser.js.map +1 -0
- package/dist/infrastructure/agent/subprocessEventStream.d.ts +26 -0
- package/dist/infrastructure/agent/subprocessEventStream.d.ts.map +1 -0
- package/dist/infrastructure/agent/subprocessEventStream.js +112 -0
- package/dist/infrastructure/agent/subprocessEventStream.js.map +1 -0
- package/dist/infrastructure/fs/FsClarifyTicketRepository.d.ts +13 -0
- package/dist/infrastructure/fs/FsClarifyTicketRepository.d.ts.map +1 -0
- package/dist/infrastructure/fs/FsClarifyTicketRepository.js +33 -0
- package/dist/infrastructure/fs/FsClarifyTicketRepository.js.map +1 -0
- package/dist/infrastructure/fs/FsDecisionRepository.d.ts +13 -0
- package/dist/infrastructure/fs/FsDecisionRepository.d.ts.map +1 -0
- package/dist/infrastructure/fs/FsDecisionRepository.js +56 -0
- package/dist/infrastructure/fs/FsDecisionRepository.js.map +1 -0
- package/dist/infrastructure/fs/FsProposalRepository.d.ts +14 -0
- package/dist/infrastructure/fs/FsProposalRepository.d.ts.map +1 -0
- package/dist/infrastructure/fs/FsProposalRepository.js +40 -0
- package/dist/infrastructure/fs/FsProposalRepository.js.map +1 -0
- package/dist/infrastructure/fs/FsRunRepository.d.ts +21 -0
- package/dist/infrastructure/fs/FsRunRepository.d.ts.map +1 -0
- package/dist/infrastructure/fs/FsRunRepository.js +88 -0
- package/dist/infrastructure/fs/FsRunRepository.js.map +1 -0
- package/dist/infrastructure/fs/FsSkillRegistry.d.ts +34 -0
- package/dist/infrastructure/fs/FsSkillRegistry.d.ts.map +1 -0
- package/dist/infrastructure/fs/FsSkillRegistry.js +143 -0
- package/dist/infrastructure/fs/FsSkillRegistry.js.map +1 -0
- package/dist/infrastructure/fs/FsStatusedJsonRepository.d.ts +35 -0
- package/dist/infrastructure/fs/FsStatusedJsonRepository.d.ts.map +1 -0
- package/dist/infrastructure/fs/FsStatusedJsonRepository.js +79 -0
- package/dist/infrastructure/fs/FsStatusedJsonRepository.js.map +1 -0
- package/dist/infrastructure/fs/FsWorkspaceRepository.d.ts +21 -0
- package/dist/infrastructure/fs/FsWorkspaceRepository.d.ts.map +1 -0
- package/dist/infrastructure/fs/FsWorkspaceRepository.js +87 -0
- package/dist/infrastructure/fs/FsWorkspaceRepository.js.map +1 -0
- package/dist/infrastructure/fs/WorkspaceRegistryFile.d.ts +17 -0
- package/dist/infrastructure/fs/WorkspaceRegistryFile.d.ts.map +1 -0
- package/dist/infrastructure/fs/WorkspaceRegistryFile.js +58 -0
- package/dist/infrastructure/fs/WorkspaceRegistryFile.js.map +1 -0
- package/dist/infrastructure/fs/frontmatter.d.ts +13 -0
- package/dist/infrastructure/fs/frontmatter.d.ts.map +1 -0
- package/dist/infrastructure/fs/frontmatter.js +46 -0
- package/dist/infrastructure/fs/frontmatter.js.map +1 -0
- package/dist/infrastructure/fs/jsonFileStore.d.ts +5 -0
- package/dist/infrastructure/fs/jsonFileStore.d.ts.map +1 -0
- package/dist/infrastructure/fs/jsonFileStore.js +29 -0
- package/dist/infrastructure/fs/jsonFileStore.js.map +1 -0
- package/dist/infrastructure/fs/paths.d.ts +22 -0
- package/dist/infrastructure/fs/paths.d.ts.map +1 -0
- package/dist/infrastructure/fs/paths.js +46 -0
- package/dist/infrastructure/fs/paths.js.map +1 -0
- package/dist/infrastructure/fs/productManifestWriter.d.ts +22 -0
- package/dist/infrastructure/fs/productManifestWriter.d.ts.map +1 -0
- package/dist/infrastructure/fs/productManifestWriter.js +75 -0
- package/dist/infrastructure/fs/productManifestWriter.js.map +1 -0
- package/dist/infrastructure/oauth/GoogleOAuth.d.ts +60 -0
- package/dist/infrastructure/oauth/GoogleOAuth.d.ts.map +1 -0
- package/dist/infrastructure/oauth/GoogleOAuth.js +114 -0
- package/dist/infrastructure/oauth/GoogleOAuth.js.map +1 -0
- package/dist/infrastructure/orphanReaper.d.ts +18 -0
- package/dist/infrastructure/orphanReaper.d.ts.map +1 -0
- package/dist/infrastructure/orphanReaper.js +42 -0
- package/dist/infrastructure/orphanReaper.js.map +1 -0
- package/dist/infrastructure/secrets/SecretStore.d.ts +36 -0
- package/dist/infrastructure/secrets/SecretStore.d.ts.map +1 -0
- package/dist/infrastructure/secrets/SecretStore.js +44 -0
- package/dist/infrastructure/secrets/SecretStore.js.map +1 -0
- package/dist/middleware/cors.d.ts +11 -0
- package/dist/middleware/cors.d.ts.map +1 -0
- package/dist/middleware/cors.js +30 -0
- package/dist/middleware/cors.js.map +1 -0
- package/dist/middleware/error.d.ts +3 -0
- package/dist/middleware/error.d.ts.map +1 -0
- package/dist/middleware/error.js +52 -0
- package/dist/middleware/error.js.map +1 -0
- package/dist/middleware/workspaceId.d.ts +10 -0
- package/dist/middleware/workspaceId.d.ts.map +1 -0
- package/dist/middleware/workspaceId.js +9 -0
- package/dist/middleware/workspaceId.js.map +1 -0
- package/dist/routes/clarify.d.ts +8 -0
- package/dist/routes/clarify.d.ts.map +1 -0
- package/dist/routes/clarify.js +84 -0
- package/dist/routes/clarify.js.map +1 -0
- package/dist/routes/decisions.d.ts +7 -0
- package/dist/routes/decisions.d.ts.map +1 -0
- package/dist/routes/decisions.js +30 -0
- package/dist/routes/decisions.js.map +1 -0
- package/dist/routes/edges.d.ts +7 -0
- package/dist/routes/edges.d.ts.map +1 -0
- package/dist/routes/edges.js +30 -0
- package/dist/routes/edges.js.map +1 -0
- package/dist/routes/health.d.ts +3 -0
- package/dist/routes/health.d.ts.map +1 -0
- package/dist/routes/health.js +10 -0
- package/dist/routes/health.js.map +1 -0
- package/dist/routes/helpers.d.ts +5 -0
- package/dist/routes/helpers.d.ts.map +1 -0
- package/dist/routes/helpers.js +14 -0
- package/dist/routes/helpers.js.map +1 -0
- package/dist/routes/model.d.ts +7 -0
- package/dist/routes/model.d.ts.map +1 -0
- package/dist/routes/model.js +12 -0
- package/dist/routes/model.js.map +1 -0
- package/dist/routes/nodes.d.ts +7 -0
- package/dist/routes/nodes.d.ts.map +1 -0
- package/dist/routes/nodes.js +47 -0
- package/dist/routes/nodes.js.map +1 -0
- package/dist/routes/oauth.d.ts +20 -0
- package/dist/routes/oauth.d.ts.map +1 -0
- package/dist/routes/oauth.js +107 -0
- package/dist/routes/oauth.js.map +1 -0
- package/dist/routes/ontology.d.ts +8 -0
- package/dist/routes/ontology.d.ts.map +1 -0
- package/dist/routes/ontology.js +21 -0
- package/dist/routes/ontology.js.map +1 -0
- package/dist/routes/proposals.d.ts +10 -0
- package/dist/routes/proposals.d.ts.map +1 -0
- package/dist/routes/proposals.js +80 -0
- package/dist/routes/proposals.js.map +1 -0
- package/dist/routes/runs.d.ts +9 -0
- package/dist/routes/runs.d.ts.map +1 -0
- package/dist/routes/runs.js +73 -0
- package/dist/routes/runs.js.map +1 -0
- package/dist/routes/skills.d.ts +9 -0
- package/dist/routes/skills.d.ts.map +1 -0
- package/dist/routes/skills.js +42 -0
- package/dist/routes/skills.js.map +1 -0
- package/dist/routes/workspaceEvents.d.ts +14 -0
- package/dist/routes/workspaceEvents.d.ts.map +1 -0
- package/dist/routes/workspaceEvents.js +37 -0
- package/dist/routes/workspaceEvents.js.map +1 -0
- package/dist/routes/workspaces.d.ts +8 -0
- package/dist/routes/workspaces.d.ts.map +1 -0
- package/dist/routes/workspaces.js +167 -0
- package/dist/routes/workspaces.js.map +1 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +33 -0
- package/dist/server.js.map +1 -0
- package/package.json +49 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { AbsolutePath, ClarifyFilter, ClarifyTicketId, WorkspaceId } from '@braidhq/schema';
|
|
2
|
+
import { ClarifyTicket, type ClarifyTicketRepository } from '@braidhq/core';
|
|
3
|
+
export interface FsClarifyTicketRepositoryOptions {
|
|
4
|
+
readonly workspaceRoots: () => Promise<ReadonlyMap<WorkspaceId, AbsolutePath>>;
|
|
5
|
+
}
|
|
6
|
+
export declare class FsClarifyTicketRepository implements ClarifyTicketRepository {
|
|
7
|
+
private readonly base;
|
|
8
|
+
constructor(options: FsClarifyTicketRepositoryOptions);
|
|
9
|
+
list(filter?: ClarifyFilter): Promise<ClarifyTicket[]>;
|
|
10
|
+
load(clarifyTicketId: ClarifyTicketId): Promise<ClarifyTicket>;
|
|
11
|
+
save(ticket: ClarifyTicket): Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=FsClarifyTicketRepository.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FsClarifyTicketRepository.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/fs/FsClarifyTicketRepository.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EACZ,aAAa,EACb,eAAe,EACf,WAAW,EACZ,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,aAAa,EAAE,KAAK,uBAAuB,EAAY,MAAM,eAAe,CAAA;AAKrF,MAAM,WAAW,gCAAgC;IAC/C,QAAQ,CAAC,cAAc,EAAE,MAAM,OAAO,CAAC,WAAW,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC,CAAA;CAC/E;AAED,qBAAa,yBAA0B,YAAW,uBAAuB;IACvE,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA2F;gBAEpG,OAAO,EAAE,gCAAgC;IAgB/C,IAAI,CAAC,MAAM,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;IAQ5D,IAAI,CAAC,eAAe,EAAE,eAAe,GAAG,OAAO,CAAC,aAAa,CAAC;IAI9D,IAAI,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;CAG3C"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { ClarifyTicket, paginate } from '@braidhq/core';
|
|
2
|
+
import { ClarifyTicket as ClarifyTicketSchema } from '@braidhq/schema';
|
|
3
|
+
import { FsStatusedJsonRepository } from './FsStatusedJsonRepository.js';
|
|
4
|
+
import { CLARIFY_STATUSES, clarifyDir } from './paths.js';
|
|
5
|
+
export class FsClarifyTicketRepository {
|
|
6
|
+
base;
|
|
7
|
+
constructor(options) {
|
|
8
|
+
this.base = new FsStatusedJsonRepository({
|
|
9
|
+
entityName: 'ClarifyTicket',
|
|
10
|
+
statuses: CLARIFY_STATUSES,
|
|
11
|
+
dirFor: clarifyDir,
|
|
12
|
+
parse: raw => new ClarifyTicket(ClarifyTicketSchema.parse(raw)),
|
|
13
|
+
serialize: entity => entity.toData(),
|
|
14
|
+
idOf: entity => entity.id,
|
|
15
|
+
statusOf: entity => entity.status,
|
|
16
|
+
workspaceIdOf: entity => entity.workspaceId,
|
|
17
|
+
}, options.workspaceRoots);
|
|
18
|
+
}
|
|
19
|
+
async list(filter) {
|
|
20
|
+
const tickets = await this.base.list({
|
|
21
|
+
...(filter?.workspaceId !== undefined ? { workspaceId: filter.workspaceId } : {}),
|
|
22
|
+
...(filter?.statuses !== undefined ? { statuses: filter.statuses } : {}),
|
|
23
|
+
});
|
|
24
|
+
return paginate(tickets, filter?.limit, filter?.offset);
|
|
25
|
+
}
|
|
26
|
+
load(clarifyTicketId) {
|
|
27
|
+
return this.base.load(clarifyTicketId);
|
|
28
|
+
}
|
|
29
|
+
save(ticket) {
|
|
30
|
+
return this.base.save(ticket);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=FsClarifyTicketRepository.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FsClarifyTicketRepository.js","sourceRoot":"","sources":["../../../src/infrastructure/fs/FsClarifyTicketRepository.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,aAAa,EAAgC,QAAQ,EAAE,MAAM,eAAe,CAAA;AACrF,OAAO,EAAE,aAAa,IAAI,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AACtE,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAA;AACxE,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAMzD,MAAM,OAAO,yBAAyB;IACnB,IAAI,CAA2F;IAEhH,YAAY,OAAyC;QACnD,IAAI,CAAC,IAAI,GAAG,IAAI,wBAAwB,CACtC;YACE,UAAU,EAAE,eAAe;YAC3B,QAAQ,EAAE,gBAAgB;YAC1B,MAAM,EAAE,UAAU;YAClB,KAAK,EAAE,GAAG,CAAC,EAAE,CAAC,IAAI,aAAa,CAAC,mBAAmB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAC/D,SAAS,EAAE,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE;YACpC,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE;YACzB,QAAQ,EAAE,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM;YACjC,aAAa,EAAE,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,WAAW;SAC5C,EACD,OAAO,CAAC,cAAc,CACvB,CAAA;IACH,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,MAAsB;QAC/B,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;YACnC,GAAG,CAAC,MAAM,EAAE,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACjF,GAAG,CAAC,MAAM,EAAE,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACzE,CAAC,CAAA;QACF,OAAO,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IACzD,CAAC;IAED,IAAI,CAAC,eAAgC;QACnC,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,CAAA;IACxC,CAAC;IAED,IAAI,CAAC,MAAqB;QACxB,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;IAC/B,CAAC;CACF"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { AbsolutePath, Decision, DecisionFilter, DecisionId, WorkspaceId } from '@braidhq/schema';
|
|
2
|
+
import { type DecisionRepository } from '@braidhq/core';
|
|
3
|
+
export interface FsDecisionRepositoryOptions {
|
|
4
|
+
readonly workspaceRoots: () => Promise<ReadonlyMap<WorkspaceId, AbsolutePath>>;
|
|
5
|
+
}
|
|
6
|
+
export declare class FsDecisionRepository implements DecisionRepository {
|
|
7
|
+
private readonly options;
|
|
8
|
+
constructor(options: FsDecisionRepositoryOptions);
|
|
9
|
+
append(decision: Decision): Promise<void>;
|
|
10
|
+
list(filter?: DecisionFilter): Promise<Decision[]>;
|
|
11
|
+
load(decisionId: DecisionId): Promise<Decision>;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=FsDecisionRepository.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FsDecisionRepository.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/fs/FsDecisionRepository.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,cAAc,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAEtG,OAAO,EAAE,KAAK,kBAAkB,EAAiB,MAAM,eAAe,CAAA;AAKtE,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,cAAc,EAAE,MAAM,OAAO,CAAC,WAAW,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC,CAAA;CAC/E;AAED,qBAAa,oBAAqB,YAAW,kBAAkB;IACjD,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,2BAA2B;IAE3D,MAAM,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IASzC,IAAI,CAAC,MAAM,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAuBlD,IAAI,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC;CAetD"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
import { NotFoundError } from '@braidhq/core';
|
|
3
|
+
import { Decision as DecisionSchema } from '@braidhq/schema';
|
|
4
|
+
import { listJsonFiles, readJsonFile, writeJsonFile } from './jsonFileStore.js';
|
|
5
|
+
import { decisionsDir } from './paths.js';
|
|
6
|
+
export class FsDecisionRepository {
|
|
7
|
+
options;
|
|
8
|
+
constructor(options) {
|
|
9
|
+
this.options = options;
|
|
10
|
+
}
|
|
11
|
+
async append(decision) {
|
|
12
|
+
const roots = await this.options.workspaceRoots();
|
|
13
|
+
const root = roots.get(decision.workspaceId);
|
|
14
|
+
if (!root)
|
|
15
|
+
throw new NotFoundError(`Workspace "${decision.workspaceId}" not registered`);
|
|
16
|
+
const targetPath = join(decisionsDir(root), `${decision.id}.json`);
|
|
17
|
+
await writeJsonFile(targetPath, decision);
|
|
18
|
+
}
|
|
19
|
+
async list(filter) {
|
|
20
|
+
const roots = await this.options.workspaceRoots();
|
|
21
|
+
const candidateWorkspaces = filter?.workspaceId
|
|
22
|
+
? new Map([[filter.workspaceId, roots.get(filter.workspaceId)]].filter(([, path]) => path))
|
|
23
|
+
: roots;
|
|
24
|
+
let decisions = [];
|
|
25
|
+
for (const [, root] of candidateWorkspaces) {
|
|
26
|
+
const files = await listJsonFiles(decisionsDir(root));
|
|
27
|
+
for (const file of files) {
|
|
28
|
+
const data = await readJsonFile(file);
|
|
29
|
+
decisions.push(DecisionSchema.parse(data));
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (filter?.actions && filter.actions.length > 0) {
|
|
33
|
+
const actions = filter.actions;
|
|
34
|
+
decisions = decisions.filter(decision => actions.includes(decision.action));
|
|
35
|
+
}
|
|
36
|
+
const start = filter?.offset ?? 0;
|
|
37
|
+
const end = filter?.limit !== undefined ? start + filter.limit : undefined;
|
|
38
|
+
return decisions.slice(start, end);
|
|
39
|
+
}
|
|
40
|
+
async load(decisionId) {
|
|
41
|
+
const roots = await this.options.workspaceRoots();
|
|
42
|
+
for (const [, root] of roots) {
|
|
43
|
+
const path = join(decisionsDir(root), `${decisionId}.json`);
|
|
44
|
+
try {
|
|
45
|
+
const data = await readJsonFile(path);
|
|
46
|
+
return DecisionSchema.parse(data);
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
if (error.code !== 'ENOENT')
|
|
50
|
+
throw error;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
throw new NotFoundError(`Decision "${decisionId}" not found`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=FsDecisionRepository.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FsDecisionRepository.js","sourceRoot":"","sources":["../../../src/infrastructure/fs/FsDecisionRepository.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { AbsolutePath, ProposalFilter, ProposalId, WorkspaceId } from '@braidhq/schema';
|
|
2
|
+
import { Proposal, type ProposalRepository } from '@braidhq/core';
|
|
3
|
+
export interface FsProposalRepositoryOptions {
|
|
4
|
+
readonly workspaceRoots: () => Promise<ReadonlyMap<WorkspaceId, AbsolutePath>>;
|
|
5
|
+
}
|
|
6
|
+
export declare class FsProposalRepository implements ProposalRepository {
|
|
7
|
+
private readonly base;
|
|
8
|
+
constructor(options: FsProposalRepositoryOptions);
|
|
9
|
+
list(filter?: ProposalFilter): Promise<Proposal[]>;
|
|
10
|
+
load(proposalId: ProposalId): Promise<Proposal>;
|
|
11
|
+
save(proposal: Proposal): Promise<void>;
|
|
12
|
+
remove(proposalId: ProposalId): Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=FsProposalRepository.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FsProposalRepository.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/fs/FsProposalRepository.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAC5F,OAAO,EAAY,QAAQ,EAAE,KAAK,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAK3E,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,cAAc,EAAE,MAAM,OAAO,CAAC,WAAW,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC,CAAA;CAC/E;AAED,qBAAa,oBAAqB,YAAW,kBAAkB;IAC7D,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAkF;gBAE3F,OAAO,EAAE,2BAA2B;IAgB1C,IAAI,CAAC,MAAM,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAYxD,IAAI,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC;IAI/C,IAAI,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAIvC,MAAM,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;CAG9C"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { paginate, Proposal } from '@braidhq/core';
|
|
2
|
+
import { Proposal as ProposalSchema } from '@braidhq/schema';
|
|
3
|
+
import { FsStatusedJsonRepository } from './FsStatusedJsonRepository.js';
|
|
4
|
+
import { PROPOSAL_STATUSES, proposalsDir } from './paths.js';
|
|
5
|
+
export class FsProposalRepository {
|
|
6
|
+
base;
|
|
7
|
+
constructor(options) {
|
|
8
|
+
this.base = new FsStatusedJsonRepository({
|
|
9
|
+
entityName: 'Proposal',
|
|
10
|
+
statuses: PROPOSAL_STATUSES,
|
|
11
|
+
dirFor: proposalsDir,
|
|
12
|
+
parse: raw => new Proposal(ProposalSchema.parse(raw)),
|
|
13
|
+
serialize: entity => entity.toData(),
|
|
14
|
+
idOf: entity => entity.id,
|
|
15
|
+
statusOf: entity => entity.status,
|
|
16
|
+
workspaceIdOf: entity => entity.workspaceId,
|
|
17
|
+
}, options.workspaceRoots);
|
|
18
|
+
}
|
|
19
|
+
async list(filter) {
|
|
20
|
+
let proposals = await this.base.list({
|
|
21
|
+
...(filter?.workspaceId !== undefined ? { workspaceId: filter.workspaceId } : {}),
|
|
22
|
+
...(filter?.statuses !== undefined ? { statuses: filter.statuses } : {}),
|
|
23
|
+
});
|
|
24
|
+
if (filter?.generatedBy && filter.generatedBy.length > 0) {
|
|
25
|
+
const skills = filter.generatedBy;
|
|
26
|
+
proposals = proposals.filter(proposal => skills.includes(proposal.generatedBy));
|
|
27
|
+
}
|
|
28
|
+
return paginate(proposals, filter?.limit, filter?.offset);
|
|
29
|
+
}
|
|
30
|
+
load(proposalId) {
|
|
31
|
+
return this.base.load(proposalId);
|
|
32
|
+
}
|
|
33
|
+
save(proposal) {
|
|
34
|
+
return this.base.save(proposal);
|
|
35
|
+
}
|
|
36
|
+
remove(proposalId) {
|
|
37
|
+
return this.base.remove(proposalId);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=FsProposalRepository.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FsProposalRepository.js","sourceRoot":"","sources":["../../../src/infrastructure/fs/FsProposalRepository.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAA2B,MAAM,eAAe,CAAA;AAC3E,OAAO,EAAE,QAAQ,IAAI,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAC5D,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAA;AACxE,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAM5D,MAAM,OAAO,oBAAoB;IACd,IAAI,CAAkF;IAEvG,YAAY,OAAoC;QAC9C,IAAI,CAAC,IAAI,GAAG,IAAI,wBAAwB,CACtC;YACE,UAAU,EAAE,UAAU;YACtB,QAAQ,EAAE,iBAAiB;YAC3B,MAAM,EAAE,YAAY;YACpB,KAAK,EAAE,GAAG,CAAC,EAAE,CAAC,IAAI,QAAQ,CAAC,cAAc,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACrD,SAAS,EAAE,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE;YACpC,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE;YACzB,QAAQ,EAAE,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM;YACjC,aAAa,EAAE,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,WAAW;SAC5C,EACD,OAAO,CAAC,cAAc,CACvB,CAAA;IACH,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,MAAuB;QAChC,IAAI,SAAS,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;YACnC,GAAG,CAAC,MAAM,EAAE,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACjF,GAAG,CAAC,MAAM,EAAE,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACzE,CAAC,CAAA;QACF,IAAI,MAAM,EAAE,WAAW,IAAI,MAAM,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACzD,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,CAAA;YACjC,SAAS,GAAG,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAA;QACjF,CAAC;QACD,OAAO,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IAC3D,CAAC;IAED,IAAI,CAAC,UAAsB;QACzB,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;IACnC,CAAC;IAED,IAAI,CAAC,QAAkB;QACrB,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IACjC,CAAC;IAED,MAAM,CAAC,UAAsB;QAC3B,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAA;IACrC,CAAC;CACF"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { RunRepository, Workspace } from '@braidhq/core';
|
|
2
|
+
import type { AbsolutePath, RunRecord, SkillEvent, SkillRunId } from '@braidhq/schema';
|
|
3
|
+
/**
|
|
4
|
+
* File-system adapter for skill-run recording.
|
|
5
|
+
*
|
|
6
|
+
* <workspaceRoot>/artifacts/runs/
|
|
7
|
+
* ├── index.jsonl (append-only summary, last-wins per runId)
|
|
8
|
+
* └── <runId>.jsonl (full SkillEvent stream for one run)
|
|
9
|
+
*
|
|
10
|
+
* Index is append-only because every concurrent write of a single workspace
|
|
11
|
+
* goes through one server process today; if that changes we'd swap to
|
|
12
|
+
* `mv tmp final` atomic rewrites or hand it to sqlite.
|
|
13
|
+
*/
|
|
14
|
+
export declare class FsRunRepository implements RunRepository {
|
|
15
|
+
saveRecord(workspace: Workspace, record: RunRecord): Promise<void>;
|
|
16
|
+
appendEvent(workspace: Workspace, runId: SkillRunId, event: SkillEvent): Promise<void>;
|
|
17
|
+
listRecords(workspace: Workspace): Promise<readonly RunRecord[]>;
|
|
18
|
+
readEvents(workspace: Workspace, runId: SkillRunId): AsyncIterable<SkillEvent>;
|
|
19
|
+
}
|
|
20
|
+
export type { AbsolutePath };
|
|
21
|
+
//# sourceMappingURL=FsRunRepository.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FsRunRepository.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/fs/FsRunRepository.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AAC7D,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAOtF;;;;;;;;;;GAUG;AACH,qBAAa,eAAgB,YAAW,aAAa;IAC7C,UAAU,CAAC,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAOlE,WAAW,CAAC,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAOtF,WAAW,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,SAAS,SAAS,EAAE,CAAC;IAyB9D,UAAU,CAAC,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,GAAG,aAAa,CAAC,UAAU,CAAC;CAiBvF;AAqBD,YAAY,EAAE,YAAY,EAAE,CAAA"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { createReadStream } from 'node:fs';
|
|
2
|
+
import { appendFile, mkdir, readFile } from 'node:fs/promises';
|
|
3
|
+
import { createInterface } from 'node:readline/promises';
|
|
4
|
+
import { RunRecord as RunRecordSchema, SkillEvent as SkillEventSchema } from '@braidhq/schema';
|
|
5
|
+
import { runEventsPath, runIndexPath, runsDir } from './paths.js';
|
|
6
|
+
/**
|
|
7
|
+
* File-system adapter for skill-run recording.
|
|
8
|
+
*
|
|
9
|
+
* <workspaceRoot>/artifacts/runs/
|
|
10
|
+
* ├── index.jsonl (append-only summary, last-wins per runId)
|
|
11
|
+
* └── <runId>.jsonl (full SkillEvent stream for one run)
|
|
12
|
+
*
|
|
13
|
+
* Index is append-only because every concurrent write of a single workspace
|
|
14
|
+
* goes through one server process today; if that changes we'd swap to
|
|
15
|
+
* `mv tmp final` atomic rewrites or hand it to sqlite.
|
|
16
|
+
*/
|
|
17
|
+
export class FsRunRepository {
|
|
18
|
+
async saveRecord(workspace, record) {
|
|
19
|
+
const root = workspace.rootPath;
|
|
20
|
+
await mkdir(runsDir(root), { recursive: true });
|
|
21
|
+
const line = `${JSON.stringify(record)}\n`;
|
|
22
|
+
await appendFile(runIndexPath(root), line, 'utf-8');
|
|
23
|
+
}
|
|
24
|
+
async appendEvent(workspace, runId, event) {
|
|
25
|
+
const root = workspace.rootPath;
|
|
26
|
+
await mkdir(runsDir(root), { recursive: true });
|
|
27
|
+
const line = `${JSON.stringify(event)}\n`;
|
|
28
|
+
await appendFile(runEventsPath(root, runId), line, 'utf-8');
|
|
29
|
+
}
|
|
30
|
+
async listRecords(workspace) {
|
|
31
|
+
const root = workspace.rootPath;
|
|
32
|
+
const path = runIndexPath(root);
|
|
33
|
+
let raw;
|
|
34
|
+
try {
|
|
35
|
+
raw = await readFile(path, 'utf-8');
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
if (error.code === 'ENOENT')
|
|
39
|
+
return [];
|
|
40
|
+
throw error;
|
|
41
|
+
}
|
|
42
|
+
// Last-write-wins per runId so progress updates collapse to a single entry.
|
|
43
|
+
const byId = new Map();
|
|
44
|
+
for (const line of raw.split('\n')) {
|
|
45
|
+
if (line.length === 0)
|
|
46
|
+
continue;
|
|
47
|
+
const parsed = safeParseRecord(line);
|
|
48
|
+
if (parsed)
|
|
49
|
+
byId.set(parsed.runId, parsed);
|
|
50
|
+
}
|
|
51
|
+
// Reverse-chronological by startedAt so the newest conversation lands at top.
|
|
52
|
+
return Array.from(byId.values()).sort((a, b) => b.startedAt.localeCompare(a.startedAt));
|
|
53
|
+
}
|
|
54
|
+
async *readEvents(workspace, runId) {
|
|
55
|
+
const path = runEventsPath(workspace.rootPath, runId);
|
|
56
|
+
const stream = createReadStream(path, { encoding: 'utf-8' });
|
|
57
|
+
const reader = createInterface({ input: stream, crlfDelay: Number.POSITIVE_INFINITY });
|
|
58
|
+
try {
|
|
59
|
+
for await (const line of reader) {
|
|
60
|
+
if (line.length === 0)
|
|
61
|
+
continue;
|
|
62
|
+
const parsed = safeParseEvent(line);
|
|
63
|
+
if (parsed)
|
|
64
|
+
yield parsed;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
finally {
|
|
68
|
+
stream.destroy();
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function safeParseRecord(line) {
|
|
73
|
+
try {
|
|
74
|
+
return RunRecordSchema.parse(JSON.parse(line));
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
function safeParseEvent(line) {
|
|
81
|
+
try {
|
|
82
|
+
return SkillEventSchema.parse(JSON.parse(line));
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=FsRunRepository.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FsRunRepository.js","sourceRoot":"","sources":["../../../src/infrastructure/fs/FsRunRepository.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAC1C,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AACxD,OAAO,EAAE,SAAS,IAAI,eAAe,EAAE,UAAU,IAAI,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAC9F,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAEjE;;;;;;;;;;GAUG;AACH,MAAM,OAAO,eAAe;IAC1B,KAAK,CAAC,UAAU,CAAC,SAAoB,EAAE,MAAiB;QACtD,MAAM,IAAI,GAAG,SAAS,CAAC,QAAQ,CAAA;QAC/B,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QAC/C,MAAM,IAAI,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAA;QAC1C,MAAM,UAAU,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,CAAA;IACrD,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,SAAoB,EAAE,KAAiB,EAAE,KAAiB;QAC1E,MAAM,IAAI,GAAG,SAAS,CAAC,QAAQ,CAAA;QAC/B,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QAC/C,MAAM,IAAI,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAA;QACzC,MAAM,UAAU,CAAC,aAAa,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,CAAA;IAC7D,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,SAAoB;QACpC,MAAM,IAAI,GAAG,SAAS,CAAC,QAAQ,CAAA;QAC/B,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC,CAAA;QAC/B,IAAI,GAAW,CAAA;QACf,IAAI,CAAC;YACH,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;QACrC,CAAC;QACD,OAAO,KAAK,EAAE,CAAC;YACb,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ;gBACpD,OAAO,EAAE,CAAA;YACX,MAAM,KAAK,CAAA;QACb,CAAC;QACD,4EAA4E;QAC5E,MAAM,IAAI,GAAG,IAAI,GAAG,EAAqB,CAAA;QACzC,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YACnC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;gBACnB,SAAQ;YACV,MAAM,MAAM,GAAG,eAAe,CAAC,IAAI,CAAC,CAAA;YACpC,IAAI,MAAM;gBACR,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAA;QAClC,CAAC;QACD,8EAA8E;QAC9E,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAA;IACzF,CAAC;IAED,KAAK,CAAC,CAAE,UAAU,CAAC,SAAoB,EAAE,KAAiB;QACxD,MAAM,IAAI,GAAG,aAAa,CAAC,SAAS,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAA;QACrD,MAAM,MAAM,GAAG,gBAAgB,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAA;QAC5D,MAAM,MAAM,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,iBAAiB,EAAE,CAAC,CAAA;QACtF,IAAI,CAAC;YACH,IAAI,KAAK,EAAE,MAAM,IAAI,IAAI,MAAM,EAAE,CAAC;gBAChC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;oBACnB,SAAQ;gBACV,MAAM,MAAM,GAAG,cAAc,CAAC,IAAI,CAAC,CAAA;gBACnC,IAAI,MAAM;oBACR,MAAM,MAAM,CAAA;YAChB,CAAC;QACH,CAAC;gBACO,CAAC;YACP,MAAM,CAAC,OAAO,EAAE,CAAA;QAClB,CAAC;IACH,CAAC;CACF;AAED,SAAS,eAAe,CAAC,IAAY;IACnC,IAAI,CAAC;QACH,OAAO,eAAe,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAA;IAChD,CAAC;IACD,MAAM,CAAC;QACL,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,IAAY;IAClC,IAAI,CAAC;QACH,OAAO,gBAAgB,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAA;IACjD,CAAC;IACD,MAAM,CAAC;QACL,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { AbsolutePath, SkillId } from '@braidhq/schema';
|
|
2
|
+
import { type PluginRegistry, SkillManifest, type SkillRegistry, type Workspace } from '@braidhq/core';
|
|
3
|
+
export interface FsSkillRegistryOptions {
|
|
4
|
+
readonly builtinSkillsRoot: AbsolutePath;
|
|
5
|
+
/**
|
|
6
|
+
* Optional plugin registry. When provided, skills declared by
|
|
7
|
+
* registered plugins are mounted under the `plugin` origin between
|
|
8
|
+
* builtins and workspace skills. Without it (e.g. in unit tests
|
|
9
|
+
* that don't compose a registry) only builtin / workspace /
|
|
10
|
+
* extension origins are discovered.
|
|
11
|
+
*/
|
|
12
|
+
readonly pluginRegistry?: PluginRegistry;
|
|
13
|
+
}
|
|
14
|
+
export declare class FsSkillRegistry implements SkillRegistry {
|
|
15
|
+
private readonly options;
|
|
16
|
+
constructor(options: FsSkillRegistryOptions);
|
|
17
|
+
list(workspace: Workspace): Promise<readonly SkillManifest[]>;
|
|
18
|
+
find(workspace: Workspace, skillId: SkillId): Promise<SkillManifest | undefined>;
|
|
19
|
+
get(workspace: Workspace, skillId: SkillId): Promise<SkillManifest>;
|
|
20
|
+
private scanSkillsRoot;
|
|
21
|
+
/**
|
|
22
|
+
* Resolve every PluginSkillRef in the registry to a parsed
|
|
23
|
+
* SkillManifest. Each ref's `directory` is converted to an absolute
|
|
24
|
+
* fs path (URL via fileURLToPath), then `SKILL.md` is read and
|
|
25
|
+
* parsed. Missing files at a plugin-declared path are an error,
|
|
26
|
+
* not a silent skip: a plugin that ships a broken ref deserves a
|
|
27
|
+
* loud startup failure, not a mysteriously-absent skill.
|
|
28
|
+
*/
|
|
29
|
+
private scanPluginSkills;
|
|
30
|
+
private scanExtensionRoot;
|
|
31
|
+
private readSkillFrontmatter;
|
|
32
|
+
private readDirSafe;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=FsSkillRegistry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FsSkillRegistry.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/fs/FsSkillRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAoB,OAAO,EAAe,MAAM,iBAAiB,CAAA;AAK3F,OAAO,EAAiB,KAAK,cAAc,EAAE,aAAa,EAAE,KAAK,aAAa,EAAE,KAAK,SAAS,EAAE,MAAM,eAAe,CAAA;AAUrH,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,iBAAiB,EAAE,YAAY,CAAA;IACxC;;;;;;OAMG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,cAAc,CAAA;CACzC;AAED,qBAAa,eAAgB,YAAW,aAAa;IACvC,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,sBAAsB;IAEtD,IAAI,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,SAAS,aAAa,EAAE,CAAC;IA4B7D,IAAI,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC;IAKhF,GAAG,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,aAAa,CAAC;YAO3D,cAAc;IAoB5B;;;;;;;OAOG;YACW,gBAAgB;YAsBhB,iBAAiB;YAoBjB,oBAAoB;YAcpB,WAAW;CAc1B"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { Buffer } from 'node:buffer';
|
|
2
|
+
import { readdir, readFile, stat } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { NotFoundError, SkillManifest } from '@braidhq/core';
|
|
6
|
+
import { AbsolutePath as AbsolutePathSchema, SkillFrontmatter as SkillFrontmatterSchema, SkillId as SkillIdSchema } from '@braidhq/schema';
|
|
7
|
+
import { parseMarkdownFrontmatter } from './frontmatter.js';
|
|
8
|
+
import { workspaceSkillExtensionsDir, workspaceSkillsDir } from './paths.js';
|
|
9
|
+
export class FsSkillRegistry {
|
|
10
|
+
options;
|
|
11
|
+
constructor(options) {
|
|
12
|
+
this.options = options;
|
|
13
|
+
}
|
|
14
|
+
async list(workspace) {
|
|
15
|
+
const builtins = await this.scanSkillsRoot(this.options.builtinSkillsRoot, 'builtin');
|
|
16
|
+
const pluginSkills = await this.scanPluginSkills();
|
|
17
|
+
const workspaceSkills = await this.scanSkillsRoot(AbsolutePathSchema.parse(workspaceSkillsDir(workspace.rootPath)), 'workspace');
|
|
18
|
+
const extensions = await this.scanExtensionRoot(AbsolutePathSchema.parse(workspaceSkillExtensionsDir(workspace.rootPath)));
|
|
19
|
+
// Precedence (later wins): builtin < plugin < workspace.
|
|
20
|
+
// Extensions don't override; they attach an EXTEND.md path to the
|
|
21
|
+
// resolved skill so SubprocessSkillRunner appends it at run time.
|
|
22
|
+
const manifests = new Map();
|
|
23
|
+
for (const manifest of builtins)
|
|
24
|
+
manifests.set(manifest.id, manifest);
|
|
25
|
+
for (const manifest of pluginSkills)
|
|
26
|
+
manifests.set(manifest.id, manifest);
|
|
27
|
+
for (const manifest of workspaceSkills)
|
|
28
|
+
manifests.set(manifest.id, manifest);
|
|
29
|
+
for (const { id, path } of extensions) {
|
|
30
|
+
const existing = manifests.get(id);
|
|
31
|
+
if (existing) {
|
|
32
|
+
const data = existing.toData();
|
|
33
|
+
manifests.set(id, new SkillManifest({ ...data, extensionPath: path }));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return [...manifests.values()];
|
|
37
|
+
}
|
|
38
|
+
async find(workspace, skillId) {
|
|
39
|
+
const all = await this.list(workspace);
|
|
40
|
+
return all.find(manifest => manifest.id === skillId);
|
|
41
|
+
}
|
|
42
|
+
async get(workspace, skillId) {
|
|
43
|
+
const manifest = await this.find(workspace, skillId);
|
|
44
|
+
if (!manifest)
|
|
45
|
+
throw new NotFoundError(`Skill "${skillId}" not found for workspace "${workspace.id}"`);
|
|
46
|
+
return manifest;
|
|
47
|
+
}
|
|
48
|
+
async scanSkillsRoot(root, origin) {
|
|
49
|
+
const entries = await this.readDirSafe(root);
|
|
50
|
+
const manifests = [];
|
|
51
|
+
for (const entry of entries) {
|
|
52
|
+
if (!entry.isDirectory())
|
|
53
|
+
continue;
|
|
54
|
+
const skillFile = AbsolutePathSchema.parse(join(root, entry.name, 'SKILL.md'));
|
|
55
|
+
const frontmatter = await this.readSkillFrontmatter(skillFile);
|
|
56
|
+
if (!frontmatter)
|
|
57
|
+
continue;
|
|
58
|
+
manifests.push(new SkillManifest({
|
|
59
|
+
id: SkillIdSchema.parse(entry.name),
|
|
60
|
+
origin,
|
|
61
|
+
path: skillFile,
|
|
62
|
+
frontmatter,
|
|
63
|
+
}));
|
|
64
|
+
}
|
|
65
|
+
return manifests;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Resolve every PluginSkillRef in the registry to a parsed
|
|
69
|
+
* SkillManifest. Each ref's `directory` is converted to an absolute
|
|
70
|
+
* fs path (URL via fileURLToPath), then `SKILL.md` is read and
|
|
71
|
+
* parsed. Missing files at a plugin-declared path are an error,
|
|
72
|
+
* not a silent skip: a plugin that ships a broken ref deserves a
|
|
73
|
+
* loud startup failure, not a mysteriously-absent skill.
|
|
74
|
+
*/
|
|
75
|
+
async scanPluginSkills() {
|
|
76
|
+
const registry = this.options.pluginRegistry;
|
|
77
|
+
if (!registry)
|
|
78
|
+
return [];
|
|
79
|
+
const refs = registry.pluginSkills();
|
|
80
|
+
const manifests = [];
|
|
81
|
+
for (const ref of refs) {
|
|
82
|
+
const dir = typeof ref.directory === 'string' ? ref.directory : fileURLToPath(ref.directory);
|
|
83
|
+
const skillFile = AbsolutePathSchema.parse(join(dir, 'SKILL.md'));
|
|
84
|
+
const frontmatter = await this.readSkillFrontmatter(skillFile);
|
|
85
|
+
if (!frontmatter)
|
|
86
|
+
throw new Error(`Plugin "${ref.contributedBy}" declared skill "${ref.id}" at ${dir} but SKILL.md is missing`);
|
|
87
|
+
manifests.push(new SkillManifest({
|
|
88
|
+
id: ref.id,
|
|
89
|
+
origin: 'plugin',
|
|
90
|
+
path: skillFile,
|
|
91
|
+
frontmatter,
|
|
92
|
+
}));
|
|
93
|
+
}
|
|
94
|
+
return manifests;
|
|
95
|
+
}
|
|
96
|
+
async scanExtensionRoot(root) {
|
|
97
|
+
const entries = await this.readDirSafe(root);
|
|
98
|
+
const results = [];
|
|
99
|
+
for (const entry of entries) {
|
|
100
|
+
if (!entry.isDirectory())
|
|
101
|
+
continue;
|
|
102
|
+
const extendPath = AbsolutePathSchema.parse(join(root, entry.name, 'EXTEND.md'));
|
|
103
|
+
try {
|
|
104
|
+
await stat(extendPath);
|
|
105
|
+
const skillId = SkillIdSchema.parse(entry.name.replace(/^braid-/, ''));
|
|
106
|
+
results.push({ id: skillId, path: extendPath });
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
if (error.code !== 'ENOENT')
|
|
110
|
+
throw error;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return results;
|
|
114
|
+
}
|
|
115
|
+
async readSkillFrontmatter(skillFile) {
|
|
116
|
+
let content;
|
|
117
|
+
try {
|
|
118
|
+
content = await readFile(skillFile, 'utf-8');
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
if (error.code === 'ENOENT')
|
|
122
|
+
return undefined;
|
|
123
|
+
throw error;
|
|
124
|
+
}
|
|
125
|
+
const { frontmatter } = parseMarkdownFrontmatter(content);
|
|
126
|
+
return SkillFrontmatterSchema.parse(frontmatter);
|
|
127
|
+
}
|
|
128
|
+
async readDirSafe(directory) {
|
|
129
|
+
try {
|
|
130
|
+
const entries = await readdir(directory, { withFileTypes: true });
|
|
131
|
+
return entries.map(entry => ({
|
|
132
|
+
name: typeof entry.name === 'string' ? entry.name : Buffer.from(entry.name).toString('utf8'),
|
|
133
|
+
isDirectory: () => entry.isDirectory(),
|
|
134
|
+
}));
|
|
135
|
+
}
|
|
136
|
+
catch (error) {
|
|
137
|
+
if (error.code === 'ENOENT')
|
|
138
|
+
return [];
|
|
139
|
+
throw error;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=FsSkillRegistry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FsSkillRegistry.js","sourceRoot":"","sources":["../../../src/infrastructure/fs/FsSkillRegistry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { AbsolutePath, WorkspaceId } from '@braidhq/schema';
|
|
2
|
+
export interface FsStatusedJsonRepositoryConfig<TEntity, TStatus extends string, TId extends string> {
|
|
3
|
+
/** Used in NotFoundError messages, e.g. "Proposal" or "ClarifyTicket". */
|
|
4
|
+
readonly entityName: string;
|
|
5
|
+
/** Exhaustive status list, used by `locate` to scan every possible folder. */
|
|
6
|
+
readonly statuses: readonly TStatus[];
|
|
7
|
+
/** Maps `(workspace root, status)` to the directory holding `{id}.json` files. */
|
|
8
|
+
readonly dirFor: (workspaceRoot: AbsolutePath, status: TStatus) => string;
|
|
9
|
+
/** Parses raw JSON read from disk into a domain entity (schema validation + class wrap). */
|
|
10
|
+
readonly parse: (raw: unknown) => TEntity;
|
|
11
|
+
/** Unwrap an entity to the plain JSON shape written to disk. */
|
|
12
|
+
readonly serialize: (entity: TEntity) => unknown;
|
|
13
|
+
readonly idOf: (entity: TEntity) => TId;
|
|
14
|
+
readonly statusOf: (entity: TEntity) => TStatus;
|
|
15
|
+
readonly workspaceIdOf: (entity: TEntity) => WorkspaceId;
|
|
16
|
+
}
|
|
17
|
+
export interface FsStatusedJsonListFilter<TStatus extends string> {
|
|
18
|
+
readonly workspaceId?: WorkspaceId;
|
|
19
|
+
readonly statuses?: readonly TStatus[];
|
|
20
|
+
}
|
|
21
|
+
export declare class FsStatusedJsonRepository<TEntity, TStatus extends string, TId extends string> {
|
|
22
|
+
private readonly config;
|
|
23
|
+
private readonly workspaceRoots;
|
|
24
|
+
constructor(config: FsStatusedJsonRepositoryConfig<TEntity, TStatus, TId>, workspaceRoots: () => Promise<ReadonlyMap<WorkspaceId, AbsolutePath>>);
|
|
25
|
+
list(filter?: FsStatusedJsonListFilter<TStatus>): Promise<TEntity[]>;
|
|
26
|
+
load(id: TId): Promise<TEntity>;
|
|
27
|
+
save(entity: TEntity): Promise<void>;
|
|
28
|
+
remove(id: TId): Promise<void>;
|
|
29
|
+
locate(id: TId): Promise<{
|
|
30
|
+
readonly path: string;
|
|
31
|
+
readonly status: TStatus;
|
|
32
|
+
} | undefined>;
|
|
33
|
+
private candidateRoots;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=FsStatusedJsonRepository.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FsStatusedJsonRepository.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/fs/FsStatusedJsonRepository.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAMhE,MAAM,WAAW,8BAA8B,CAAC,OAAO,EAAE,OAAO,SAAS,MAAM,EAAE,GAAG,SAAS,MAAM;IACjG,0EAA0E;IAC1E,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,8EAA8E;IAC9E,QAAQ,CAAC,QAAQ,EAAE,SAAS,OAAO,EAAE,CAAA;IACrC,kFAAkF;IAClF,QAAQ,CAAC,MAAM,EAAE,CAAC,aAAa,EAAE,YAAY,EAAE,MAAM,EAAE,OAAO,KAAK,MAAM,CAAA;IACzE,4FAA4F;IAC5F,QAAQ,CAAC,KAAK,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAA;IACzC,gEAAgE;IAChE,QAAQ,CAAC,SAAS,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,CAAA;IAChD,QAAQ,CAAC,IAAI,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,GAAG,CAAA;IACvC,QAAQ,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,CAAA;IAC/C,QAAQ,CAAC,aAAa,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,WAAW,CAAA;CACzD;AAED,MAAM,WAAW,wBAAwB,CAAC,OAAO,SAAS,MAAM;IAC9D,QAAQ,CAAC,WAAW,CAAC,EAAE,WAAW,CAAA;IAClC,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,OAAO,EAAE,CAAA;CACvC;AAED,qBAAa,wBAAwB,CAAC,OAAO,EAAE,OAAO,SAAS,MAAM,EAAE,GAAG,SAAS,MAAM;IAErF,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,cAAc;gBADd,MAAM,EAAE,8BAA8B,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,EAC7D,cAAc,EAAE,MAAM,OAAO,CAAC,WAAW,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;IAGlF,IAAI,CAAC,MAAM,CAAC,EAAE,wBAAwB,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAiBpE,IAAI,CAAC,EAAE,EAAE,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC;IAQ/B,IAAI,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAepC,MAAM,CAAC,EAAE,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IAO9B,MAAM,CAAC,EAAE,EAAE,GAAG,GAAG,OAAO,CAAC;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;KAAE,GAAG,SAAS,CAAC;YAkBjF,cAAc;CAS7B"}
|