chapterhouse 0.3.6 → 0.3.7

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.
@@ -1,5 +1,6 @@
1
- import { existsSync, readFileSync, readdirSync, statSync } from 'fs';
1
+ import { existsSync } from 'fs';
2
2
  import { join } from 'path';
3
+ import { FSStorageProvider, SquadState, NotFoundError } from '@bradygaster/squad-sdk';
3
4
  import { getDb } from '../store/db.js';
4
5
  // ---------------------------------------------------------------------------
5
6
  // DB schema — created lazily on first use
@@ -101,47 +102,38 @@ export async function resolveProjectSquad(projectPath) {
101
102
  catch {
102
103
  // SDK not available — use manual path resolution
103
104
  }
104
- // Enumerate agents from .squad/agents/
105
- const agentsDir = join(resolvedSquadDir, 'agents');
105
+ // Enumerate agents from .squad/agents/ via SDK AgentsCollection.
106
+ // FSStorageProvider wraps the same fs calls with typed returns and ENOENT safety.
106
107
  const agents = [];
107
- if (existsSync(agentsDir)) {
108
- let entries = [];
109
- try {
110
- entries = readdirSync(agentsDir);
111
- }
112
- catch { /* ignore read errors */ }
113
- for (const entry of entries) {
114
- const agentDir = join(agentsDir, entry);
115
- try {
116
- if (!statSync(agentDir).isDirectory())
117
- continue;
118
- }
119
- catch {
120
- continue;
121
- }
122
- const charterPath = join(agentDir, 'charter.md');
123
- if (!existsSync(charterPath))
124
- continue;
125
- let charterContent = '';
108
+ const stateRoot = resolvedSquadDir.endsWith('/.squad')
109
+ ? resolvedSquadDir.slice(0, -'/.squad'.length)
110
+ : projectPath;
111
+ try {
112
+ const storage = new FSStorageProvider();
113
+ const state = SquadState.fromStorage(storage, stateRoot);
114
+ const agentNames = await state.agents.list();
115
+ for (const name of agentNames) {
116
+ const charterPath = join(resolvedSquadDir, 'agents', name, 'charter.md');
117
+ let charterContent;
126
118
  try {
127
- charterContent = readFileSync(charterPath, 'utf-8');
119
+ charterContent = await state.agents.get(name).charter();
128
120
  }
129
- catch {
121
+ catch (err) {
122
+ if (err instanceof NotFoundError)
123
+ continue; // no charter.md — not a valid agent
130
124
  continue;
131
125
  }
132
- const slug = entry;
133
- const role = extractRoleFromCharter(charterContent);
134
- const description = extractDescriptionFromCharter(charterContent);
135
126
  agents.push({
136
- slug,
137
- mention: `@${slug}`,
138
- role,
139
- description,
127
+ slug: name,
128
+ mention: `@${name}`,
129
+ role: extractRoleFromCharter(charterContent),
130
+ description: extractDescriptionFromCharter(charterContent),
140
131
  charterPath,
141
132
  origin: 'project-squad',
142
133
  });
143
134
  }
144
135
  }
136
+ catch { /* SDK unavailable — agents list stays empty */ }
145
137
  // Load squad config via SDK with fallback to empty config
146
138
  let squadConfig = {};
147
139
  try {
@@ -228,25 +220,21 @@ export async function loadProjectSquad(projectPath) {
228
220
  : undefined,
229
221
  origin: 'project-squad',
230
222
  }));
231
- // Repo wins: re-sync any new agents that appeared since last cache
232
- const repoAgentsDir = join(row.squad_dir, 'agents');
233
- if (existsSync(repoAgentsDir)) {
234
- const repoDirs = readdirSync(repoAgentsDir).filter(e => {
235
- try {
236
- return statSync(join(repoAgentsDir, e)).isDirectory();
237
- }
238
- catch {
239
- return false;
240
- }
241
- });
223
+ // Repo wins: re-sync any new agents that appeared since last cache.
224
+ // Use SDK AgentsCollection.list() so we stay consistent with resolveProjectSquad().
225
+ try {
226
+ const cacheStorage = new FSStorageProvider();
227
+ const cacheState = SquadState.fromStorage(cacheStorage, row.project_root);
228
+ const repoAgentNames = await cacheState.agents.list();
242
229
  const cachedSlugs = new Set(agents.map(a => a.slug));
243
- for (const slug of repoDirs) {
230
+ for (const slug of repoAgentNames) {
244
231
  if (!cachedSlugs.has(slug)) {
245
232
  // New agent in repo not in cache — trigger full reload
246
233
  return resolveProjectSquad(projectPath);
247
234
  }
248
235
  }
249
236
  }
237
+ catch { /* SDK unavailable — skip new-agent check */ }
250
238
  return {
251
239
  projectRoot: row.project_root,
252
240
  squadDir: row.squad_dir,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chapterhouse",
3
- "version": "0.3.6",
3
+ "version": "0.3.7",
4
4
  "description": "Chapterhouse — a team-level AI assistant for engineering teams, built on the GitHub Copilot SDK. Web UI only.",
5
5
  "bin": {
6
6
  "chapterhouse": "dist/cli.js"