toga-ai 1.0.47 → 1.0.48

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/knowledge.js CHANGED
@@ -183,6 +183,19 @@ function cmdManifest() {
183
183
  /* front-end|hybrid> --q=<keywords to match feature docs> */
184
184
  /* ------------------------------------------------------------------ */
185
185
 
186
+ function extractSection(body, heading) {
187
+ const lines = body.split(/\r?\n/);
188
+ const want = ('## ' + heading).toLowerCase();
189
+ const start = lines.findIndex(l => l.trim().toLowerCase() === want);
190
+ if (start === -1) return '';
191
+ const out = [];
192
+ for (let i = start + 1; i < lines.length; i++) {
193
+ if (/^##\s/.test(lines[i])) break;
194
+ out.push(lines[i]);
195
+ }
196
+ return out.join('\n').trim();
197
+ }
198
+
186
199
  function cmdPreflight(args) {
187
200
  const registry = loadRegistry();
188
201
  const chosen = String(args.repos || '').split(',').map(s => s.trim()).filter(Boolean);
@@ -217,21 +230,27 @@ function cmdPreflight(args) {
217
230
  const fileInfo = (rel) => ({ path: rel, exists: fs.existsSync(path.join(ROOT, rel.split('/').join(path.sep))) });
218
231
  const matchQ = (d) => !q || (((d.data.title || '') + ' ' + (d.data.files || []).join(' ') + ' ' + d.body).toLowerCase().includes(q));
219
232
 
220
- // per-repo inventory; feature docs only for explicitly chosen repos
233
+ // per-repo inventory. Chosen repos load FULL architecture + matched features.
234
+ // Non-chosen repos (deps, incl. framework core) get their `## Summary` inlined
235
+ // here so kickoff reads zero extra files for them — full doc lazy on demand.
221
236
  const repoOut = loadSet.map(repo => {
222
237
  const e = registry.find(x => x.repo === repo);
223
238
  const fw = e ? e.framework : '';
224
239
  const repoDir = path.join(ROOT, fw, 'apps', repo);
225
240
  const isChosen = chosenSet.has(repo);
241
+ const archRel = `${fw}/apps/${repo}/architecture.md`;
242
+ const archDoc = docs.find(d => d.rel === archRel);
226
243
  let features = [];
227
244
  if (isChosen) {
228
245
  features = docs
229
246
  .filter(d => d.file.startsWith(repoDir + path.sep) && d.data.type !== 'architecture' && matchQ(d))
230
247
  .map(d => ({ path: d.rel, title: d.data.title || '', files: (d.data.files || []).join(', ') }));
231
248
  }
249
+ const summary = (!isChosen && archDoc) ? (extractSection(archDoc.body, 'Summary') || firstSentence(archDoc.body)) : '';
232
250
  return {
233
251
  repo, framework: fw, project: e ? e.project : '', role: e ? e.role : '', chosen: isChosen,
234
- architecture: fileInfo(`${fw}/apps/${repo}/architecture.md`),
252
+ architecture: fileInfo(archRel),
253
+ summary,
235
254
  features,
236
255
  };
237
256
  });
@@ -265,16 +284,22 @@ function cmdPreflight(args) {
265
284
  };
266
285
  }
267
286
 
268
- // ordered read list — mirrors kickoff Step 4: core arch repo arch+features → standards → client
287
+ // ordered read list — mirrors kickoff Step 4 precedence (core first, then chosen
288
+ // repos + features, then standards, then client). Chosen repos → a FULL architecture
289
+ // read; non-chosen → an inline-`summary` entry the skill should NOT open unless it
290
+ // needs deeper detail (lazy:true). Core ordering preserved so foundational context
291
+ // (even when summarized) comes before app context.
269
292
  const reads = [];
270
- for (const r of repoOut.filter(r => r.role === 'core')) {
271
- reads.push({ label: 'core-architecture', repo: r.repo, ...r.architecture });
272
- for (const f of r.features) reads.push({ label: 'feature', repo: r.repo, path: f.path, exists: true, title: f.title });
273
- }
274
- for (const r of repoOut.filter(r => r.role !== 'core')) {
275
- reads.push({ label: r.chosen ? 'repo-architecture' : 'dep-architecture', repo: r.repo, ...r.architecture });
276
- for (const f of r.features) reads.push({ label: 'feature', repo: r.repo, path: f.path, exists: true, title: f.title });
277
- }
293
+ const pushRepoRead = (r) => {
294
+ if (r.chosen) {
295
+ reads.push({ label: 'repo-architecture', repo: r.repo, path: r.architecture.path, exists: r.architecture.exists });
296
+ for (const f of r.features) reads.push({ label: 'feature', repo: r.repo, path: f.path, exists: true, title: f.title });
297
+ } else {
298
+ reads.push({ label: 'architecture-summary', repo: r.repo, role: r.role, path: r.architecture.path, exists: r.architecture.exists, lazy: true, summary: r.summary });
299
+ }
300
+ };
301
+ for (const r of repoOut.filter(r => r.role === 'core')) pushRepoRead(r);
302
+ for (const r of repoOut.filter(r => r.role !== 'core')) pushRepoRead(r);
278
303
  for (const s of standards) reads.push({ label: 'standard', path: s.path, exists: s.exists });
279
304
  if (client) {
280
305
  reads.push({ label: 'client-profile', path: client.profile.path, exists: client.profile.exists });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toga-ai",
3
- "version": "1.0.47",
3
+ "version": "1.0.48",
4
4
  "description": "TOGA Technology Team Claude Knowledge System — shared AI coding harness with skills, knowledge base CLI, and project installer for Claude Code.",
5
5
  "keywords": [
6
6
  "claude",
@@ -144,10 +144,13 @@ node "<TEAM_REPO>/knowledge.js" kickoff-preflight \
144
144
 
145
145
  It prints minified JSON:
146
146
  - `loadSet` — framework core(s) + chosen repos + transitive `dependsOn`, in load order.
147
- - `repos[]` — each with `architecture` `{path,exists}`, `role`, `chosen`, and matched
148
- `features[]` (features are returned only for the repos the developer chose, not deps).
147
+ - `repos[]` — each with `architecture` `{path,exists}`, `role`, `chosen`, an inline
148
+ `summary` (for non-chosen repos), and matched `features[]` (features returned only for the
149
+ repos the developer chose, not deps).
149
150
  - `standards[]` and `client` `{title, profile, docs[]}` — both `{path,exists}`-flagged.
150
- - `reads[]` — **the ordered list of knowledge files to read**, each `{label, path, exists}`.
151
+ - `reads[]` — **the ordered work list** (see Step 4). Full-read entries carry `{label, path,
152
+ exists}`; non-chosen repos instead carry `{label:'architecture-summary', summary, lazy:true}`
153
+ with the Summary text inlined so no file read is needed.
151
154
  - `unknown[]` — any `--repos` value not in the registry (run New-repo onboarding for each).
152
155
 
153
156
  **Do not run `deps` or `search` separately, and do not probe the filesystem for these docs.**
@@ -163,14 +166,25 @@ Never ask for a repo not in `loadSet`.
163
166
 
164
167
  ## Step 4 — Load the knowledge
165
168
 
166
- Read every entry in the preflight `reads[]` array **in order**, resolving each `path`
167
- against `<TEAM_REPO>/knowledge/`. Skip entries with `exists:false` — that doc isn't written
168
- yet; note it in the Step 5 summary as "no knowledge captured yet."
169
-
170
- The `reads[]` order already encodes the correct precedence (framework core architecture
171
- chosen-repo architecture + matched features dep architecture standards client profile +
172
- client docs), and already unions across `1.0/` and `2.0/` for a both-frameworks session. You
173
- do not need to re-derive this order or run any further `search`.
169
+ Walk the preflight `reads[]` array **in order**. Each entry is one of:
170
+
171
+ - **`lazy:true` (label `architecture-summary`)** a repo the developer did NOT choose as
172
+ focus (a dependency or framework core). The entry already carries an inline `summary`
173
+ string **use that summary as your context for this repo; do NOT open the file.** Only
174
+ open its `path` later, on demand, if a task actually requires that repo's deep internals.
175
+ This is the token-saving default: foundational orientation without loading the full doc.
176
+ - **Any other entry (no `lazy` flag)** the chosen repos' architecture + matched feature
177
+ docs, standards, and client docs. **Read these in full**, resolving `path` against
178
+ `<TEAM_REPO>/knowledge/`.
179
+ - **`exists:false`** — skip; that doc isn't written yet. Note it in the Step 5 summary as
180
+ "no knowledge captured yet."
181
+
182
+ The `reads[]` order already encodes the correct precedence (core first, then chosen-repo
183
+ architecture + matched features, then standards, then client profile + client docs) and
184
+ already unions across `1.0/` and `2.0/`. Do not re-derive this order or run further `search`.
185
+
186
+ If, while working, you find you need the full architecture of a summarized (`lazy`) repo,
187
+ just read its `path` then — that's the intended lazy-load, not a kickoff failure.
174
188
 
175
189
  **Do NOT create or modify any `CLAUDE.md` stub** — kickoff only reads. A blank session is a
176
190
  valid choice; this skill is opt-in.