@codedrifters/configulator 0.0.257 → 0.0.259
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/lib/index.d.mts +222 -6
- package/lib/index.d.ts +223 -7
- package/lib/index.js +994 -48
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +991 -48
- package/lib/index.mjs.map +1 -1
- package/package.json +1 -1
package/lib/index.mjs
CHANGED
|
@@ -1295,6 +1295,98 @@ var baseBundle = {
|
|
|
1295
1295
|
].join("\n"),
|
|
1296
1296
|
tags: ["project"]
|
|
1297
1297
|
},
|
|
1298
|
+
{
|
|
1299
|
+
name: "source-quality-verification",
|
|
1300
|
+
description: "Source tier hierarchy (T1\u2013T4), conflict resolution, temporal validity, and source-annotation format for research-producing agents",
|
|
1301
|
+
scope: AGENT_RULE_SCOPE.ALWAYS,
|
|
1302
|
+
content: [
|
|
1303
|
+
"# Source Quality & Verification",
|
|
1304
|
+
"",
|
|
1305
|
+
"All research-producing agents must follow this source hierarchy when",
|
|
1306
|
+
"writing profiles and reference documents. The tiers govern which",
|
|
1307
|
+
"source to prefer when claims conflict and when time-sensitive claims",
|
|
1308
|
+
"need re-verification.",
|
|
1309
|
+
"",
|
|
1310
|
+
"## Source Tier Hierarchy",
|
|
1311
|
+
"",
|
|
1312
|
+
"### T1 \u2014 Primary Living",
|
|
1313
|
+
"",
|
|
1314
|
+
"Authoritative sources that update when reality changes.",
|
|
1315
|
+
"Use these for current-state claims. Examples:",
|
|
1316
|
+
"",
|
|
1317
|
+
"- Official product docs and API references",
|
|
1318
|
+
"- Company about / leadership / team pages",
|
|
1319
|
+
"- Live government registries (SEC EDGAR, Companies House)",
|
|
1320
|
+
"- Current-role LinkedIn profiles",
|
|
1321
|
+
"- Investor relations pages",
|
|
1322
|
+
"",
|
|
1323
|
+
"### T2 \u2014 Primary Snapshot",
|
|
1324
|
+
"",
|
|
1325
|
+
"Authoritative but time-stamped sources straight from the subject.",
|
|
1326
|
+
"Trust for current state only when fresh (< 6 months) and no T1",
|
|
1327
|
+
"source contradicts them. Examples:",
|
|
1328
|
+
"",
|
|
1329
|
+
"- Press releases from the entity",
|
|
1330
|
+
"- Earnings transcripts and investor calls",
|
|
1331
|
+
"- Regulatory filings (10-K, 10-Q, 8-K)",
|
|
1332
|
+
"- Official announcements and conference presentations",
|
|
1333
|
+
"",
|
|
1334
|
+
"### T3 \u2014 Secondary",
|
|
1335
|
+
"",
|
|
1336
|
+
"Third-party sources that interpret or re-report primary material.",
|
|
1337
|
+
"Good for context and triangulation; T1 wins on conflict. Examples:",
|
|
1338
|
+
"",
|
|
1339
|
+
"- News articles and trade press",
|
|
1340
|
+
"- Industry reports and analyst research",
|
|
1341
|
+
"- Database aggregators (Crunchbase, PitchBook, Owler)",
|
|
1342
|
+
"",
|
|
1343
|
+
"### T4 \u2014 Self-Reported / Marketing",
|
|
1344
|
+
"",
|
|
1345
|
+
"Promotional or unverified sources. Use for discovery and leads only",
|
|
1346
|
+
"\u2014 never as the sole source for a factual claim, and always note the",
|
|
1347
|
+
"self-reported nature in the annotation. Examples:",
|
|
1348
|
+
"",
|
|
1349
|
+
"- Vendor comparison pages and customer testimonials on vendor sites",
|
|
1350
|
+
"- Social-media posts",
|
|
1351
|
+
"- Job postings",
|
|
1352
|
+
"- Wikipedia",
|
|
1353
|
+
"",
|
|
1354
|
+
"## Conflict Resolution",
|
|
1355
|
+
"",
|
|
1356
|
+
"Higher tier wins. Within the same tier, more recent wins. If a newer",
|
|
1357
|
+
"T2 source contradicts an older T1 source on a time-sensitive claim,",
|
|
1358
|
+
"flag for re-verification \u2014 the T1 source may simply not have been",
|
|
1359
|
+
"updated yet.",
|
|
1360
|
+
"",
|
|
1361
|
+
"## Temporal Validity",
|
|
1362
|
+
"",
|
|
1363
|
+
"Some claims decay faster than others. When a fast-decay claim comes",
|
|
1364
|
+
"from a source older than 6 months, agents **must** attempt to",
|
|
1365
|
+
"corroborate it with a T1 living source. If no T1 source is available,",
|
|
1366
|
+
"add an inline note: `_(source: YYYY-MM, may need re-verification)_`.",
|
|
1367
|
+
"",
|
|
1368
|
+
"| Decay | Re-verify if source older than | Typical claims |",
|
|
1369
|
+
"|-------|-------------------------------|----------------|",
|
|
1370
|
+
"| **Fast** | 6 months | Leadership roles, employee count, pricing, product features, funding status, office locations |",
|
|
1371
|
+
"| **Slow** | 18 months | Founding year, ownership structure, core business description, industry classification, HQ location |",
|
|
1372
|
+
"| **Stable** | Verify once, note source date | Historical facts (acquisition dates, founding story), published financials for a specific period |",
|
|
1373
|
+
"",
|
|
1374
|
+
"## Source Annotation Format",
|
|
1375
|
+
"",
|
|
1376
|
+
"In the `## Sources` section of profiles and reference documents,",
|
|
1377
|
+
"annotate each source with its tier and date:",
|
|
1378
|
+
"",
|
|
1379
|
+
"```",
|
|
1380
|
+
"1. [Company Leadership Page](https://...) \u2014 T1, accessed 2026-04",
|
|
1381
|
+
"2. [Company press release](https://...) \u2014 T2, published 2026-02",
|
|
1382
|
+
"3. [TechCrunch coverage](https://...) \u2014 T3, published 2025-11",
|
|
1383
|
+
"```",
|
|
1384
|
+
"",
|
|
1385
|
+
"Use `accessed YYYY-MM` for living sources (T1) and `published YYYY-MM`",
|
|
1386
|
+
"for snapshot sources (T2, T3, T4)."
|
|
1387
|
+
].join("\n"),
|
|
1388
|
+
tags: ["workflow"]
|
|
1389
|
+
},
|
|
1298
1390
|
{
|
|
1299
1391
|
name: "issue-conventions",
|
|
1300
1392
|
description: "Issue title prefixes, GitHub issue type mapping, prerequisite issues",
|
|
@@ -2242,7 +2334,7 @@ var bcmWriterBundle = {
|
|
|
2242
2334
|
// src/agent/bundles/company-profile.ts
|
|
2243
2335
|
var companyProfileAnalystSubAgent = {
|
|
2244
2336
|
name: "company-profile-analyst",
|
|
2245
|
-
description: "Researches an external company (competitor, vendor, partner, customer, etc.) from public sources and produces a structured markdown profile, then enqueues downstream `people:research` and `software:research` issues for notable people and software products surfaced during profiling. One company per session, tracked by company:* GitHub issue labels.",
|
|
2337
|
+
description: "Researches an external company (competitor, vendor, partner, customer, etc.) from public sources and produces a structured markdown profile, then enqueues downstream `people:research` and `software:research` issues for notable people and software products surfaced during profiling. Also handles profile enrichment against business-model canvases (`company:match`), maintenance refreshes on a configurable staleness cadence (`company:refresh`), and cross-profile competitive synthesis for a segment (`company:analyze`). One company or segment per session, tracked by company:* GitHub issue labels.",
|
|
2246
2338
|
model: AGENT_MODEL.POWERFUL,
|
|
2247
2339
|
maxTurns: 80,
|
|
2248
2340
|
platforms: { cursor: { exclude: true } },
|
|
@@ -2250,9 +2342,11 @@ var companyProfileAnalystSubAgent = {
|
|
|
2250
2342
|
"# Company Profile Analyst Agent",
|
|
2251
2343
|
"",
|
|
2252
2344
|
"You research a single external company from public sources and write",
|
|
2253
|
-
"a structured markdown profile
|
|
2254
|
-
"
|
|
2255
|
-
"
|
|
2345
|
+
"a structured markdown profile, then maintain it as facts drift and",
|
|
2346
|
+
"roll profiles up into segment-level competitive analysis. Each",
|
|
2347
|
+
"session claims one GitHub issue \u2014 one phase, one company (or one",
|
|
2348
|
+
"segment for `company:analyze`) \u2014 and produces files on disk plus",
|
|
2349
|
+
"optional follow-up research issues.",
|
|
2256
2350
|
"",
|
|
2257
2351
|
"This agent is **domain-neutral**. It makes no assumptions about what",
|
|
2258
2352
|
"the consuming project sells, which industry it serves, or which",
|
|
@@ -2269,7 +2363,9 @@ var companyProfileAnalystSubAgent = {
|
|
|
2269
2363
|
"## Design Principles",
|
|
2270
2364
|
"",
|
|
2271
2365
|
"1. **One company per session.** Never profile two companies in a",
|
|
2272
|
-
" single session, even if they came up together.",
|
|
2366
|
+
" single session, even if they came up together. The `company:analyze`",
|
|
2367
|
+
" phase is the single exception \u2014 it synthesizes across multiple",
|
|
2368
|
+
" profiles in **one segment** but never researches a new company.",
|
|
2273
2369
|
"2. **Public sources only.** Use the company's own site, press, product",
|
|
2274
2370
|
" docs, job listings, and other public material. Do not attempt to",
|
|
2275
2371
|
" access gated or paywalled content unless the invoking issue body",
|
|
@@ -2289,6 +2385,12 @@ var companyProfileAnalystSubAgent = {
|
|
|
2289
2385
|
" `people-profile` bundle via `people:research` issues; software",
|
|
2290
2386
|
" products are handed off to the `software-profile` bundle via",
|
|
2291
2387
|
" `software:research` issues.",
|
|
2388
|
+
"7. **Enrichment is not re-research.** `company:match` reads existing",
|
|
2389
|
+
" docs and edits the profile; it never runs web searches. Refresh is",
|
|
2390
|
+
" the only maintenance phase that goes back to the public web.",
|
|
2391
|
+
"8. **Synthesis waits for drafts.** `company:analyze` blocks if any",
|
|
2392
|
+
" `company:draft` issues for the target segment are still open.",
|
|
2393
|
+
" Never publish a partial landscape.",
|
|
2292
2394
|
"",
|
|
2293
2395
|
"---",
|
|
2294
2396
|
"",
|
|
@@ -2323,6 +2425,24 @@ var companyProfileAnalystSubAgent = {
|
|
|
2323
2425
|
"\u2502 bounded notes \u2502 \u2502 the configured path \u2502 \u2502 for people and \u2502",
|
|
2324
2426
|
"\u2502 file \u2502 \u2502 \u2502 \u2502 software surfaced \u2502",
|
|
2325
2427
|
"\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518",
|
|
2428
|
+
" \u2502",
|
|
2429
|
+
" \u25BC",
|
|
2430
|
+
" \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510",
|
|
2431
|
+
" \u2502 4. MATCH \u2502",
|
|
2432
|
+
" \u2502 Enrich profile \u2502",
|
|
2433
|
+
" \u2502 with business- \u2502",
|
|
2434
|
+
" \u2502 model and segment \u2502",
|
|
2435
|
+
" \u2502 context. No web. \u2502",
|
|
2436
|
+
" \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518",
|
|
2437
|
+
"",
|
|
2438
|
+
"\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510",
|
|
2439
|
+
"\u2502 5. REFRESH \u2502 (cadence-driven, \u2502 6. ANALYZE \u2502",
|
|
2440
|
+
"\u2502 Re-verify an \u2502 or on-demand) \u2502 Synthesize across \u2502",
|
|
2441
|
+
"\u2502 existing profile \u2502 \u2502 profiles in one \u2502",
|
|
2442
|
+
"\u2502 with targeted web \u2502 \u2502 segment. No web. \u2502",
|
|
2443
|
+
"\u2502 searches. Update \u2502 \u2502 Blocks on open \u2502",
|
|
2444
|
+
"\u2502 in place. \u2502 \u2502 company:draft. \u2502",
|
|
2445
|
+
"\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518",
|
|
2326
2446
|
"```",
|
|
2327
2447
|
"",
|
|
2328
2448
|
"**Issue labels encode the phase:**",
|
|
@@ -2330,41 +2450,87 @@ var companyProfileAnalystSubAgent = {
|
|
|
2330
2450
|
"| Label | Phase | Session work |",
|
|
2331
2451
|
"|-------|-------|-------------|",
|
|
2332
2452
|
"| `company:research` | 1. Research | Gather public sources. Write a bounded research-notes file. Create the draft issue. |",
|
|
2333
|
-
"| `company:draft` | 2. Draft | Read the research notes. Write the structured profile to `<PROFILES_DIR>`. Create the
|
|
2453
|
+
"| `company:draft` | 2. Draft | Read the research notes. Write the structured profile to `<PROFILES_DIR>`. Create the followup and (if enabled) match issues. |",
|
|
2334
2454
|
"| `company:followup` | 3. Followup | Read the profile. Enqueue people/software research issues for items surfaced in the profile. |",
|
|
2455
|
+
"| `company:match` | 4. Match | Read the profile. Enrich it with business-model, segment, and size context from existing docs. Bidirectionally cross-link matched business-model files. No web. |",
|
|
2456
|
+
"| `company:refresh` | 5. Refresh | Read an existing profile. Run 4\u20136 targeted web searches for recent developments. Update the profile in place and add a revision-history entry. |",
|
|
2457
|
+
"| `company:analyze` | 6. Analyze | Read every profile in one segment. Write a segment-level competitive-analysis document combining feature matrix, positioning, and strategic implications. No web. |",
|
|
2335
2458
|
"",
|
|
2336
2459
|
"All issues also carry `type:company-profile` and a `status:*` label.",
|
|
2337
2460
|
"",
|
|
2338
|
-
"**Issue count per company cycle:** 1 research + 1 draft + 0\u20131 followup
|
|
2339
|
-
"**2\
|
|
2340
|
-
"
|
|
2461
|
+
"**Issue count per company cycle:** 1 research + 1 draft + 0\u20131 followup +",
|
|
2462
|
+
"0\u20131 match = **2\u20134 sessions** on the initial cycle. `company:refresh`",
|
|
2463
|
+
"and `company:analyze` are independent downstream cycles that run on",
|
|
2464
|
+
"their own cadence.",
|
|
2341
2465
|
"",
|
|
2342
2466
|
"**Shortened paths:**",
|
|
2343
2467
|
"- Research phase determines the company is out of scope (not",
|
|
2344
2468
|
" relevant, insufficient public material) \u2192 research issue closes",
|
|
2345
2469
|
" with a justification and no downstream issues are created \u2192 **1 session**.",
|
|
2346
|
-
"- Short profile with no follow-ups needed
|
|
2470
|
+
"- Short profile with no follow-ups needed and no business-model",
|
|
2471
|
+
" context to match against \u2192 **2 sessions**.",
|
|
2472
|
+
"- Refresh that finds no material change \u2192 **1 session** (revision-",
|
|
2473
|
+
" history entry only, profile body unchanged).",
|
|
2347
2474
|
"",
|
|
2348
2475
|
"---",
|
|
2349
2476
|
"",
|
|
2350
2477
|
"## Configurable Paths",
|
|
2351
2478
|
"",
|
|
2352
2479
|
"The pipeline uses these placeholders. Consuming projects override the",
|
|
2353
|
-
"defaults by passing paths in the `/profile-company
|
|
2354
|
-
"or
|
|
2480
|
+
"defaults by passing paths in the `/profile-company`, `/match-company`,",
|
|
2481
|
+
"`/refresh-company`, or `/analyze-segment` skill invocations, or by",
|
|
2482
|
+
"extending this rule in their own `agentConfig.rules`.",
|
|
2355
2483
|
"",
|
|
2356
2484
|
"| Placeholder | Meaning | Default |",
|
|
2357
2485
|
"|-------------|---------|---------|",
|
|
2358
2486
|
"| `<COMPANY_ROOT>` | Root folder for company profiles | `docs/companies/` |",
|
|
2359
2487
|
"| `<PROFILES_DIR>` | Final company profile files | `<COMPANY_ROOT>/profiles/` |",
|
|
2360
2488
|
"| `<NOTES_DIR>` | Research-notes files from Phase 1 | `<COMPANY_ROOT>/notes/` |",
|
|
2489
|
+
"| `<ANALYSIS_DIR>` | Segment-level competitive-analysis documents from Phase 6 | `<COMPANY_ROOT>/analysis/` |",
|
|
2361
2490
|
"| `<COMPANY_SLUG>` | Short kebab-case slug identifying the company | derived from the company name |",
|
|
2491
|
+
"| `<SEGMENT_SLUG>` | Short kebab-case slug identifying the industry segment | derived from the segment name |",
|
|
2492
|
+
"| `<BUSINESS_MODELS_ROOT>` | Where existing business-model canvases live (consumed by Phase 4) | `docs/src/content/docs/industry-research/` |",
|
|
2362
2493
|
"| `<PEOPLE_PROFILES_DIR>` | Where existing people profiles live (for duplicate detection during followup) | `docs/people/profiles/` |",
|
|
2363
2494
|
"| `<SOFTWARE_PROFILES_DIR>` | Where existing software profiles live (for duplicate detection during followup) | `docs/software/profiles/` |",
|
|
2364
2495
|
"",
|
|
2365
2496
|
"If `docs/src/content/docs/project-context.md` specifies a different company-research",
|
|
2366
2497
|
"tree (for example by reusing the research-pipeline deliverables",
|
|
2367
2498
|
"folder), prefer that. Otherwise fall back to the defaults above.",
|
|
2499
|
+
"Business-model canvases are managed by the `business-models` bundle \u2014",
|
|
2500
|
+
"this agent is a **read-only consumer** of `<BUSINESS_MODELS_ROOT>`,",
|
|
2501
|
+
"with the single exception of appending a bidirectional cross-link",
|
|
2502
|
+
"back to the matched profile (Phase 4, Step 6).",
|
|
2503
|
+
"",
|
|
2504
|
+
"---",
|
|
2505
|
+
"",
|
|
2506
|
+
"## Refresh Cadence",
|
|
2507
|
+
"",
|
|
2508
|
+
"Profiles go stale. Companies launch products, raise rounds, rotate",
|
|
2509
|
+
"leadership, or pivot. The pipeline supports a configurable refresh",
|
|
2510
|
+
"cadence so `company:refresh` issues can be filed on a schedule",
|
|
2511
|
+
"without hardcoding the interval:",
|
|
2512
|
+
"",
|
|
2513
|
+
"- **Default staleness threshold:** 180 days from the profile's",
|
|
2514
|
+
" `date` frontmatter.",
|
|
2515
|
+
"- **Override:** the invoking issue body may specify a `refresh_days: N`",
|
|
2516
|
+
" field, or the consuming project may set a project-wide default in",
|
|
2517
|
+
" `docs/src/content/docs/project-context.md` (look for a",
|
|
2518
|
+
" `## Refresh Cadence` section) or in `agentConfig.rules`.",
|
|
2519
|
+
"",
|
|
2520
|
+
"When the `/refresh-company` skill is invoked for a slug that already",
|
|
2521
|
+
"has a profile:",
|
|
2522
|
+
"",
|
|
2523
|
+
"- If the profile is **younger** than the staleness threshold, the",
|
|
2524
|
+
" skill exits with a message pointing to the existing profile. Pass",
|
|
2525
|
+
" `force: true` in the issue body to refresh anyway.",
|
|
2526
|
+
"- If the profile is **older** than the staleness threshold, the",
|
|
2527
|
+
" pipeline files a `company:refresh` issue and Phase 5 updates the",
|
|
2528
|
+
" existing file in place, preserving its slug and bumping the",
|
|
2529
|
+
" `date` frontmatter.",
|
|
2530
|
+
"",
|
|
2531
|
+
"Refresh mode never changes the profile's primary type without an",
|
|
2532
|
+
"explicit override in the refresh request \u2014 type changes are material",
|
|
2533
|
+
"and warrant a human review step.",
|
|
2368
2534
|
"",
|
|
2369
2535
|
"---",
|
|
2370
2536
|
"",
|
|
@@ -2373,7 +2539,8 @@ var companyProfileAnalystSubAgent = {
|
|
|
2373
2539
|
"Run this loop exactly once per session. Never start a second issue.",
|
|
2374
2540
|
"",
|
|
2375
2541
|
"1. Claim one open `type:company-profile` issue using phase priority:",
|
|
2376
|
-
" `company:research` > `company:draft` > `company:followup
|
|
2542
|
+
" `company:research` > `company:draft` > `company:followup` >",
|
|
2543
|
+
" `company:match` > `company:refresh` > `company:analyze`.",
|
|
2377
2544
|
"2. Transition `status:ready` \u2192 `status:in-progress` and create the",
|
|
2378
2545
|
" branch per your project's branch-naming convention.",
|
|
2379
2546
|
"3. Execute the phase handler that matches the issue's `company:*`",
|
|
@@ -2482,8 +2649,10 @@ var companyProfileAnalystSubAgent = {
|
|
|
2482
2649
|
" company_type: <one of the taxonomy values>",
|
|
2483
2650
|
" website: <primary URL>",
|
|
2484
2651
|
" date: YYYY-MM-DD",
|
|
2652
|
+
" refresh_days: <N, default 180>",
|
|
2485
2653
|
" parent_issue: <N>",
|
|
2486
2654
|
" notes: <NOTES_DIR>/<COMPANY_SLUG>.notes.md",
|
|
2655
|
+
" referencedIn: []",
|
|
2487
2656
|
" ---",
|
|
2488
2657
|
"",
|
|
2489
2658
|
" # <company name>",
|
|
@@ -2512,6 +2681,10 @@ var companyProfileAnalystSubAgent = {
|
|
|
2512
2681
|
" <stack hints from job listings, product docs, public engineering",
|
|
2513
2682
|
" content \u2014 each bullet cited>",
|
|
2514
2683
|
"",
|
|
2684
|
+
" ## Market Position",
|
|
2685
|
+
" <which segment(s) they play in, where they sit on the",
|
|
2686
|
+
" competitive map, who they compete with \u2014 cited>",
|
|
2687
|
+
"",
|
|
2515
2688
|
" ## Positioning / Differentiation",
|
|
2516
2689
|
" <how they describe themselves and how they differ from adjacent",
|
|
2517
2690
|
" companies \u2014 use their own language, cited, rather than inferred>",
|
|
@@ -2525,6 +2698,11 @@ var companyProfileAnalystSubAgent = {
|
|
|
2525
2698
|
" - **Products / software to evaluate:** <list of candidate product",
|
|
2526
2699
|
" names>",
|
|
2527
2700
|
"",
|
|
2701
|
+
" ## Revision History",
|
|
2702
|
+
" | Date | Changes |",
|
|
2703
|
+
" |------|---------|",
|
|
2704
|
+
" | YYYY-MM-DD | Initial profile |",
|
|
2705
|
+
"",
|
|
2528
2706
|
" ## Sources",
|
|
2529
2707
|
" - <source URL> \u2014 <date accessed>",
|
|
2530
2708
|
" ```",
|
|
@@ -2535,7 +2713,13 @@ var companyProfileAnalystSubAgent = {
|
|
|
2535
2713
|
" note in the draft issue's closing comment that no follow-up is",
|
|
2536
2714
|
" needed.",
|
|
2537
2715
|
"",
|
|
2538
|
-
"5. **
|
|
2716
|
+
"5. **File a `company:match` issue** (depending on this draft issue)",
|
|
2717
|
+
" so the profile gets enriched against the project's business-model",
|
|
2718
|
+
" canvases. Skip the match issue only when the invoking project has",
|
|
2719
|
+
" no business-model canvases at all (Phase 4 will detect and exit",
|
|
2720
|
+
" gracefully in that case).",
|
|
2721
|
+
"",
|
|
2722
|
+
"6. **Commit and push** the profile file. Close the draft issue.",
|
|
2539
2723
|
"",
|
|
2540
2724
|
"---",
|
|
2541
2725
|
"",
|
|
@@ -2631,12 +2815,321 @@ var companyProfileAnalystSubAgent = {
|
|
|
2631
2815
|
"",
|
|
2632
2816
|
"---",
|
|
2633
2817
|
"",
|
|
2818
|
+
"## Phase 4: Match (`company:match`)",
|
|
2819
|
+
"",
|
|
2820
|
+
"**Goal:** Enrich an existing profile with business-model and segment",
|
|
2821
|
+
"context from the adjacent business-model canvases and industry-",
|
|
2822
|
+
"segment descriptions already tracked in the project. Create",
|
|
2823
|
+
"bidirectional cross-links so both the profile and the matched",
|
|
2824
|
+
"business-model document reference each other.",
|
|
2825
|
+
"",
|
|
2826
|
+
"This phase is **enrichment of a known profile**, not entity",
|
|
2827
|
+
"deduplication \u2014 the profile already exists. It is triggered in two",
|
|
2828
|
+
"ways:",
|
|
2829
|
+
"",
|
|
2830
|
+
"1. **Downstream of draft.** Phase 2 files a `company:match` issue",
|
|
2831
|
+
" for every new profile once the draft is committed.",
|
|
2832
|
+
"2. **Downstream of a new business-model canvas.** When the",
|
|
2833
|
+
" `business-models` bundle lands a new canvas (or the orchestrator",
|
|
2834
|
+
" scans for profiles that should be re-matched), `company:match`",
|
|
2835
|
+
" issues are filed for each existing profile that might fit the new",
|
|
2836
|
+
" canvas.",
|
|
2837
|
+
"",
|
|
2838
|
+
"**Budget:** No web searches. Read existing docs, edit the profile,",
|
|
2839
|
+
"cross-link the matched business-model file. Anything that cannot be",
|
|
2840
|
+
"decided from the project's own documents is flagged in the profile's",
|
|
2841
|
+
"`## Risks / Open Questions` section, not resolved with a web search.",
|
|
2842
|
+
"",
|
|
2843
|
+
"### Steps",
|
|
2844
|
+
"",
|
|
2845
|
+
"1. **Read the target profile** at the path referenced in the issue",
|
|
2846
|
+
" body. The issue body must carry the profile path; if it does not,",
|
|
2847
|
+
" close the issue with `status:needs-attention` and stop.",
|
|
2848
|
+
"",
|
|
2849
|
+
"2. **Identify the profile's industry / segment context.** Read the",
|
|
2850
|
+
" profile's `## Summary`, `## Market Position`, and `referencedIn`",
|
|
2851
|
+
" frontmatter to determine which industry(ies) and segment(s) the",
|
|
2852
|
+
" company plays in.",
|
|
2853
|
+
"",
|
|
2854
|
+
"3. **Scan `<BUSINESS_MODELS_ROOT>` for candidate canvases.** Walk",
|
|
2855
|
+
" the directory tree looking for business-model documents in",
|
|
2856
|
+
" relevant segments. A typical layout is",
|
|
2857
|
+
" `<BUSINESS_MODELS_ROOT>/<industry>/segments/<segment>/business-model.md`,",
|
|
2858
|
+
" but consuming projects may use a different layout \u2014 accept any",
|
|
2859
|
+
" markdown file named `business-model*.md` (or matching the pattern",
|
|
2860
|
+
" the consuming project declares in `docs/src/content/docs/project-context.md`).",
|
|
2861
|
+
" If the directory does not exist or contains no canvases, exit",
|
|
2862
|
+
" gracefully: add a short note to the profile's `## Risks / Open",
|
|
2863
|
+
" Questions` section and close the issue.",
|
|
2864
|
+
"",
|
|
2865
|
+
"4. **For each candidate canvas, score the match.** For each canvas:",
|
|
2866
|
+
" - Read the Customer Segments, Key Activities, Value Propositions,",
|
|
2867
|
+
" and Revenue Streams sections (if present).",
|
|
2868
|
+
" - Decide whether the profiled company fits one of the customer",
|
|
2869
|
+
" segments (customer match), offers a competing value proposition",
|
|
2870
|
+
" (competitor match), supplies a key activity as a vendor (vendor",
|
|
2871
|
+
" match), or is named explicitly as a partner (partner match).",
|
|
2872
|
+
" - If the canvas documents size variations (SMB / mid-market /",
|
|
2873
|
+
" enterprise), pick the variation that matches the profiled",
|
|
2874
|
+
" company's size signals (headcount, funding, revenue).",
|
|
2875
|
+
" - Record matches only when the evidence is unambiguous \u2014 skip",
|
|
2876
|
+
" weak or inferred matches.",
|
|
2877
|
+
"",
|
|
2878
|
+
"5. **Enrich the profile.** Add or update a `## Business Model",
|
|
2879
|
+
" Context` section using the template below. Place it after",
|
|
2880
|
+
" `## Market Position` and before `## Positioning / Differentiation`",
|
|
2881
|
+
" so the synthesis flows naturally:",
|
|
2882
|
+
"",
|
|
2883
|
+
" ```markdown",
|
|
2884
|
+
" ## Business Model Context",
|
|
2885
|
+
"",
|
|
2886
|
+
" ### Matched Business Models",
|
|
2887
|
+
"",
|
|
2888
|
+
" | Business Model | Segment | Match Type | Size Variation |",
|
|
2889
|
+
" |----------------|---------|------------|----------------|",
|
|
2890
|
+
" | [<canvas title>](<relative path to business-model.md>) | <segment> | <customer / competitor / vendor / partner> | <SMB / Mid-Market / Enterprise or `n/a`> |",
|
|
2891
|
+
"",
|
|
2892
|
+
" ### Segment Classification",
|
|
2893
|
+
"",
|
|
2894
|
+
" - **Primary segment:** [<segment name>](<relative path to segment index>) \u2014 <one sentence on fit>",
|
|
2895
|
+
" - **Secondary segment(s):** <list or `n/a`>",
|
|
2896
|
+
"",
|
|
2897
|
+
" ### Size Classification",
|
|
2898
|
+
"",
|
|
2899
|
+
" Based on <headcount>, <revenue/funding>, and <any other size",
|
|
2900
|
+
" signal>, this company matches the **<SMB / Mid-Market /",
|
|
2901
|
+
" Enterprise>** variation in the <segment> business model.",
|
|
2902
|
+
" ```",
|
|
2903
|
+
"",
|
|
2904
|
+
" Use `_No matched business models in <BUSINESS_MODELS_ROOT>._` as",
|
|
2905
|
+
" the table body when Step 3 found candidates but Step 4 scored",
|
|
2906
|
+
" zero matches.",
|
|
2907
|
+
"",
|
|
2908
|
+
"6. **Update the matched business-model documents bidirectionally.**",
|
|
2909
|
+
" For every row in the matched-models table, append a cross-link",
|
|
2910
|
+
" to the canvas's own Traceability (or Sources) section \u2014 do not",
|
|
2911
|
+
" rewrite the canvas body. A single line is enough:",
|
|
2912
|
+
"",
|
|
2913
|
+
" ```markdown",
|
|
2914
|
+
" - **Profiled company:** [<company name>](<relative path to profile.md>) \u2014 match type: <customer / competitor / vendor / partner>",
|
|
2915
|
+
" ```",
|
|
2916
|
+
"",
|
|
2917
|
+
" If a canvas already lists this profile, do not duplicate the line.",
|
|
2918
|
+
" If the canvas has no Traceability or Sources section, skip the",
|
|
2919
|
+
" canvas and flag it in the profile's `## Risks / Open Questions`",
|
|
2920
|
+
" section rather than inventing a new section in someone else's",
|
|
2921
|
+
" document.",
|
|
2922
|
+
"",
|
|
2923
|
+
"7. **Update the profile's `referencedIn` frontmatter.** Add the",
|
|
2924
|
+
" relative paths of every matched business-model document and",
|
|
2925
|
+
" segment index so downstream audit tooling can traverse the link",
|
|
2926
|
+
" graph without re-scanning the tree.",
|
|
2927
|
+
"",
|
|
2928
|
+
"8. **Append a revision-history row.**",
|
|
2929
|
+
"",
|
|
2930
|
+
" ```markdown",
|
|
2931
|
+
" | YYYY-MM-DD | Matched to business models: <comma-separated segment list> |",
|
|
2932
|
+
" ```",
|
|
2933
|
+
"",
|
|
2934
|
+
"9. **Commit and push.** Close the match issue with a short comment",
|
|
2935
|
+
" summarizing the matched segments.",
|
|
2936
|
+
"",
|
|
2937
|
+
"---",
|
|
2938
|
+
"",
|
|
2939
|
+
"## Phase 5: Refresh (`company:refresh`)",
|
|
2940
|
+
"",
|
|
2941
|
+
"**Goal:** Re-verify an existing profile with a small number of",
|
|
2942
|
+
"targeted web searches for recent developments, then update the",
|
|
2943
|
+
"profile in place.",
|
|
2944
|
+
"",
|
|
2945
|
+
"**Budget:** 4\u20136 targeted web searches, focused on recent activity.",
|
|
2946
|
+
"Do not redo the full research-phase sweep.",
|
|
2947
|
+
"",
|
|
2948
|
+
"### Steps",
|
|
2949
|
+
"",
|
|
2950
|
+
"1. **Read the existing profile** at the path referenced in the issue",
|
|
2951
|
+
" body. If the profile file is missing, close the issue with",
|
|
2952
|
+
" `status:needs-attention` and stop.",
|
|
2953
|
+
"",
|
|
2954
|
+
"2. **Confirm the staleness threshold.** Compare the profile's `date`",
|
|
2955
|
+
" frontmatter against today's date and the `refresh_days`",
|
|
2956
|
+
" frontmatter (or the project default from the Refresh Cadence",
|
|
2957
|
+
" section above). If the profile is younger than the threshold and",
|
|
2958
|
+
" the issue body does not set `force: true`, close the issue with",
|
|
2959
|
+
" a short comment and stop \u2014 do not burn the search budget.",
|
|
2960
|
+
"",
|
|
2961
|
+
"3. **Run 4\u20136 targeted searches.** Focus on:",
|
|
2962
|
+
" - `<company name>` + recent news, press releases, or blog posts",
|
|
2963
|
+
" - Product launches, feature changes, or pricing updates",
|
|
2964
|
+
" - Funding rounds, acquisitions, or material ownership changes",
|
|
2965
|
+
" - Leadership changes (CEO, CTO, CPO, notable departures/arrivals)",
|
|
2966
|
+
" - New partnerships, certifications, or regulatory milestones",
|
|
2967
|
+
"",
|
|
2968
|
+
"4. **Update the profile in place.** Edit the affected sections with",
|
|
2969
|
+
" the new information. Cite every new claim. Preserve the slug and",
|
|
2970
|
+
" the original `parent_issue` field. Bump the `date` frontmatter to",
|
|
2971
|
+
" today's date.",
|
|
2972
|
+
"",
|
|
2973
|
+
"5. **Do not silently re-type the company.** If the refresh surfaces",
|
|
2974
|
+
" evidence that the company's primary type has changed (e.g., an",
|
|
2975
|
+
" industry-player that now sells a directly competing product),",
|
|
2976
|
+
" flag it in `## Risks / Open Questions` and stop \u2014 do **not**",
|
|
2977
|
+
" rewrite the `company_type` frontmatter without an explicit",
|
|
2978
|
+
" override in the refresh issue body (`retype: <new type>`).",
|
|
2979
|
+
"",
|
|
2980
|
+
"6. **Append a revision-history row.** Summarize the delta in one",
|
|
2981
|
+
" line:",
|
|
2982
|
+
"",
|
|
2983
|
+
" ```markdown",
|
|
2984
|
+
" | YYYY-MM-DD | Refreshed: <one-line summary of what changed> |",
|
|
2985
|
+
" ```",
|
|
2986
|
+
"",
|
|
2987
|
+
" When the search budget finds no material change, the row still",
|
|
2988
|
+
" appears so the next scheduled refresh knows this profile was",
|
|
2989
|
+
" reviewed:",
|
|
2990
|
+
"",
|
|
2991
|
+
" ```markdown",
|
|
2992
|
+
" | YYYY-MM-DD | Refreshed: no material change |",
|
|
2993
|
+
" ```",
|
|
2994
|
+
"",
|
|
2995
|
+
"7. **Update reference entries** (if the project tracks company",
|
|
2996
|
+
" references under research directories). If the company's",
|
|
2997
|
+
" relevance to a research area has shifted \u2014 for example, it is no",
|
|
2998
|
+
" longer a live competitor, or it now plays in a new segment \u2014",
|
|
2999
|
+
" update the corresponding entry under `referencedIn` and the",
|
|
3000
|
+
" research-area doc that links to this profile.",
|
|
3001
|
+
"",
|
|
3002
|
+
"8. **Commit and push.** Close the refresh issue with a short comment",
|
|
3003
|
+
" summarizing the delta (or `no material change`).",
|
|
3004
|
+
"",
|
|
3005
|
+
"---",
|
|
3006
|
+
"",
|
|
3007
|
+
"## Phase 6: Analyze (`company:analyze`)",
|
|
3008
|
+
"",
|
|
3009
|
+
"**Goal:** Produce a segment-level competitive analysis by",
|
|
3010
|
+
"synthesizing every profile in the target segment. The deliverable",
|
|
3011
|
+
"is one markdown document under `<ANALYSIS_DIR>` combining a",
|
|
3012
|
+
"feature-comparison matrix, a positioning map, and the strategic",
|
|
3013
|
+
"implications for the consuming project.",
|
|
3014
|
+
"",
|
|
3015
|
+
"**Budget:** No web searches. Pure synthesis from existing profiles",
|
|
3016
|
+
"and (optionally) existing product docs the consuming project",
|
|
3017
|
+
"maintains.",
|
|
3018
|
+
"",
|
|
3019
|
+
"### Steps",
|
|
3020
|
+
"",
|
|
3021
|
+
"1. **Read the segment scope from the issue body.** It must carry",
|
|
3022
|
+
" `<SEGMENT_SLUG>` plus the path of every profile to include (or a",
|
|
3023
|
+
" glob that resolves to them). If the issue body is ambiguous,",
|
|
3024
|
+
" close with `status:needs-attention` and stop.",
|
|
3025
|
+
"",
|
|
3026
|
+
"2. **Block on open draft issues.** Query for open",
|
|
3027
|
+
" `company:draft` issues whose title or body mentions the segment",
|
|
3028
|
+
" slug:",
|
|
3029
|
+
"",
|
|
3030
|
+
" ```bash",
|
|
3031
|
+
" gh issue list \\",
|
|
3032
|
+
" --label 'company:draft' --state open \\",
|
|
3033
|
+
" --search '<SEGMENT_SLUG> in:title,body' \\",
|
|
3034
|
+
" --json number,title --limit 200",
|
|
3035
|
+
" ```",
|
|
3036
|
+
"",
|
|
3037
|
+
" If the query returns any issues, this analyze issue must block on",
|
|
3038
|
+
" them. Add `Depends on: #<N>` lines for every open draft, apply",
|
|
3039
|
+
" `status:blocked`, remove `status:in-progress`, and stop \u2014 **do",
|
|
3040
|
+
" not publish a partial landscape**. The issue will be eligible",
|
|
3041
|
+
" again once the drafts close.",
|
|
3042
|
+
"",
|
|
3043
|
+
"3. **Read every in-scope profile.** Collect each profile's Summary,",
|
|
3044
|
+
" Offering, Classification, Market Position, Positioning /",
|
|
3045
|
+
" Differentiation, and Risks / Open Questions sections.",
|
|
3046
|
+
"",
|
|
3047
|
+
"4. **Derive a feature axis.** Build the feature axis from the",
|
|
3048
|
+
" union of bullets across each profile's Offering section (and, if",
|
|
3049
|
+
" present, a project-maintained feature taxonomy under",
|
|
3050
|
+
" `<BUSINESS_MODELS_ROOT>`). Do **not** invent features not",
|
|
3051
|
+
" represented in at least one profile or the project's taxonomy.",
|
|
3052
|
+
"",
|
|
3053
|
+
"5. **Write the analysis document** to",
|
|
3054
|
+
" `<ANALYSIS_DIR>/<SEGMENT_SLUG>.md` using the template below. Use",
|
|
3055
|
+
" `_Not available in profiles._` in any cell a profile does not",
|
|
3056
|
+
" document. Never fabricate a `Yes/No` from a missing field.",
|
|
3057
|
+
"",
|
|
3058
|
+
" ```markdown",
|
|
3059
|
+
" ---",
|
|
3060
|
+
' title: "<segment name> Competitive Analysis"',
|
|
3061
|
+
" slug: <SEGMENT_SLUG>",
|
|
3062
|
+
" segment: <segment name>",
|
|
3063
|
+
" date: YYYY-MM-DD",
|
|
3064
|
+
" status: draft",
|
|
3065
|
+
" profiles:",
|
|
3066
|
+
" - <relative path to profile 1>",
|
|
3067
|
+
" - <relative path to profile 2>",
|
|
3068
|
+
" ---",
|
|
3069
|
+
"",
|
|
3070
|
+
" # <segment name> Competitive Analysis",
|
|
3071
|
+
"",
|
|
3072
|
+
" ## Market Overview",
|
|
3073
|
+
" <landscape summary \u2014 total players, market structure, trends",
|
|
3074
|
+
" visible from the profiles>",
|
|
3075
|
+
"",
|
|
3076
|
+
" ## Feature Comparison Matrix",
|
|
3077
|
+
" | Feature | <Company A> | <Company B> | <Company C> |",
|
|
3078
|
+
" |---------|-------------|-------------|-------------|",
|
|
3079
|
+
" | <feature> | Yes / No / Partial | ... | ... |",
|
|
3080
|
+
"",
|
|
3081
|
+
" ## Pricing Comparison",
|
|
3082
|
+
" <pricing tiers across profiles, where disclosed>",
|
|
3083
|
+
"",
|
|
3084
|
+
" ## Positioning Map",
|
|
3085
|
+
" <where each player sits \u2014 by price vs. feature depth, or by",
|
|
3086
|
+
" segment focus. Textual description; link to an external diagram",
|
|
3087
|
+
" if the consuming project maintains one.>",
|
|
3088
|
+
"",
|
|
3089
|
+
" ## Strengths & Vulnerabilities",
|
|
3090
|
+
" | Company | Key Strength | Key Vulnerability |",
|
|
3091
|
+
" |---------|--------------|-------------------|",
|
|
3092
|
+
" | <company> | <strength> | <vulnerability> |",
|
|
3093
|
+
"",
|
|
3094
|
+
" ## Strategic Implications",
|
|
3095
|
+
" <which features matter most, where the consuming project can",
|
|
3096
|
+
" differentiate, what pricing the landscape supports, and which",
|
|
3097
|
+
" competitive threats to watch>",
|
|
3098
|
+
"",
|
|
3099
|
+
" ## Recommended Actions",
|
|
3100
|
+
" | Action | Priority | Rationale |",
|
|
3101
|
+
" |--------|----------|-----------|",
|
|
3102
|
+
" | <action> | High / Medium / Low | <why> |",
|
|
3103
|
+
"",
|
|
3104
|
+
" ## Sources",
|
|
3105
|
+
" - <relative path to profile 1>",
|
|
3106
|
+
" - <relative path to profile 2>",
|
|
3107
|
+
"",
|
|
3108
|
+
" ## Revision History",
|
|
3109
|
+
" | Date | Changes |",
|
|
3110
|
+
" |------|---------|",
|
|
3111
|
+
" | YYYY-MM-DD | Initial analysis |",
|
|
3112
|
+
" ```",
|
|
3113
|
+
"",
|
|
3114
|
+
"6. **Do not edit the underlying profiles.** `company:analyze` is a",
|
|
3115
|
+
" synthesis phase \u2014 profiles are **inputs only**. Any cross-link",
|
|
3116
|
+
" from a profile to the analysis document should be added by a",
|
|
3117
|
+
" follow-up `company:match` pass, not by this phase.",
|
|
3118
|
+
"",
|
|
3119
|
+
"7. **Commit and push.** Close the analyze issue with a short",
|
|
3120
|
+
" comment naming the analysis document path.",
|
|
3121
|
+
"",
|
|
3122
|
+
"---",
|
|
3123
|
+
"",
|
|
2634
3124
|
"## Output Boundaries",
|
|
2635
3125
|
"",
|
|
2636
3126
|
"This agent writes **only** to:",
|
|
2637
3127
|
"",
|
|
2638
3128
|
"- `<NOTES_DIR>/` \u2014 research-notes files (Phase 1)",
|
|
2639
|
-
"- `<PROFILES_DIR>/` \u2014 company profiles (Phase 2, updated in
|
|
3129
|
+
"- `<PROFILES_DIR>/` \u2014 company profiles (Phase 2, updated in Phases",
|
|
3130
|
+
" 3, 4, and 5)",
|
|
3131
|
+
"- `<ANALYSIS_DIR>/` \u2014 segment-level competitive-analysis documents",
|
|
3132
|
+
" (Phase 6)",
|
|
2640
3133
|
"",
|
|
2641
3134
|
"In Phase 3, this agent also **creates `people:research` and",
|
|
2642
3135
|
"`software:research` issues** for people and software products",
|
|
@@ -2645,18 +3138,33 @@ var companyProfileAnalystSubAgent = {
|
|
|
2645
3138
|
"`people-profile-analyst` and `software-profile-analyst` agents, which",
|
|
2646
3139
|
"pick up the issues this pipeline creates.",
|
|
2647
3140
|
"",
|
|
2648
|
-
"
|
|
2649
|
-
"
|
|
2650
|
-
"
|
|
2651
|
-
"
|
|
2652
|
-
"
|
|
2653
|
-
"
|
|
3141
|
+
"In Phase 4, this agent appends a single bidirectional cross-link",
|
|
3142
|
+
"line to matched business-model documents under",
|
|
3143
|
+
"`<BUSINESS_MODELS_ROOT>`. It never rewrites the canvas body, adds",
|
|
3144
|
+
"new canvas sections, or otherwise mutates business-model content \u2014",
|
|
3145
|
+
"that remains the responsibility of the `business-models` bundle.",
|
|
3146
|
+
"",
|
|
3147
|
+
"In Phase 5, this agent only updates an existing profile in place \u2014",
|
|
3148
|
+
"it never forks a new profile under a different slug.",
|
|
3149
|
+
"",
|
|
3150
|
+
"In Phase 6, this agent only writes a new segment-level analysis",
|
|
3151
|
+
"document. It never edits the underlying company profiles.",
|
|
3152
|
+
"",
|
|
3153
|
+
"The pipeline produces **company profiles, notes, and segment",
|
|
3154
|
+
"analyses**. Deeper research on people or products is delegated to",
|
|
3155
|
+
"downstream research pipelines via `people:research` and",
|
|
3156
|
+
"`software:research` issues \u2014 this agent never writes person",
|
|
3157
|
+
"profiles, software profiles, product evaluations, or",
|
|
3158
|
+
"requirement-style documents itself. Keep this boundary clean so",
|
|
3159
|
+
"the company-profile pipeline stays generic.",
|
|
2654
3160
|
"",
|
|
2655
3161
|
"---",
|
|
2656
3162
|
"",
|
|
2657
3163
|
"## Rules",
|
|
2658
3164
|
"",
|
|
2659
3165
|
"- **One company per session.** Never profile two companies back-to-back.",
|
|
3166
|
+
" `company:analyze` is the single exception \u2014 it synthesizes one",
|
|
3167
|
+
" segment per session, not one company.",
|
|
2660
3168
|
"- **Persist before closing.** Every phase must write its output file",
|
|
2661
3169
|
" before closing its issue.",
|
|
2662
3170
|
"- **Cite everything.** Profile claims without source citations do not",
|
|
@@ -2677,10 +3185,24 @@ var companyProfileAnalystSubAgent = {
|
|
|
2677
3185
|
" and products that are genuinely relevant to the framing of this",
|
|
2678
3186
|
" profile. Do not open issues for every name or product mentioned in",
|
|
2679
3187
|
" passing.",
|
|
2680
|
-
"- **Produce profiles, not requirement
|
|
3188
|
+
"- **Produce profiles and analyses, not requirement documents.** Do",
|
|
2681
3189
|
" not open `type:requirement` or formal evaluation issues from this",
|
|
2682
3190
|
" pipeline. Follow-up research is scoped through `people:research`",
|
|
2683
|
-
" and `software:research` only."
|
|
3191
|
+
" and `software:research` only.",
|
|
3192
|
+
"- **Match is read-mostly.** Phase 4 edits the target profile and",
|
|
3193
|
+
" appends one line to each matched business-model document. It never",
|
|
3194
|
+
" rewrites canvas bodies, never runs web searches, and never edits",
|
|
3195
|
+
" other profiles.",
|
|
3196
|
+
"- **Refresh respects the cadence.** Phase 5 exits early when the",
|
|
3197
|
+
" profile is younger than the staleness threshold and `force: true`",
|
|
3198
|
+
" is not set. It always appends a revision-history row so the next",
|
|
3199
|
+
" scheduled run knows the profile was reviewed.",
|
|
3200
|
+
"- **Analyze blocks on open drafts.** Phase 6 refuses to publish a",
|
|
3201
|
+
" partial landscape. If any `company:draft` issues for the target",
|
|
3202
|
+
" segment are still open, the analyze issue is marked",
|
|
3203
|
+
" `status:blocked` with `Depends on:` lines pointing at each draft.",
|
|
3204
|
+
"- **Refresh, don't fork.** When a profile exists and is past its",
|
|
3205
|
+
" cadence, update in place rather than creating a new slug."
|
|
2684
3206
|
].join("\n")
|
|
2685
3207
|
};
|
|
2686
3208
|
var profileCompanySkill = {
|
|
@@ -2725,8 +3247,8 @@ var profileCompanySkill = {
|
|
|
2725
3247
|
" company name, selected type, framing, and any overrides.",
|
|
2726
3248
|
"2. Execute Phase 1 (Research) of the company-profile-analyst agent.",
|
|
2727
3249
|
"3. Phase 1 creates the `company:draft` issue. Phase 2 may create a",
|
|
2728
|
-
" `company:followup` issue
|
|
2729
|
-
" `Depends on:` predecessor.",
|
|
3250
|
+
" `company:followup` issue **and** a `company:match` issue. Each",
|
|
3251
|
+
" downstream issue declares its `Depends on:` predecessor.",
|
|
2730
3252
|
"",
|
|
2731
3253
|
"## Output",
|
|
2732
3254
|
"",
|
|
@@ -2736,38 +3258,265 @@ var profileCompanySkill = {
|
|
|
2736
3258
|
" (handed off to the `people-profile` bundle)",
|
|
2737
3259
|
"- `software:research` issues for software products surfaced in the",
|
|
2738
3260
|
" profile (handed off to the `software-profile` bundle)",
|
|
3261
|
+
"- A `company:match` issue so the profile is enriched against the",
|
|
3262
|
+
" project's business-model canvases",
|
|
2739
3263
|
"- This pipeline produces **company profiles only** \u2014 it does not",
|
|
2740
3264
|
" write person profiles, software profiles, product evaluations, or",
|
|
2741
|
-
" comparative analyses itself."
|
|
3265
|
+
" comparative analyses itself. Segment-level analysis is produced by",
|
|
3266
|
+
" the separate `/analyze-segment` skill."
|
|
3267
|
+
].join("\n")
|
|
3268
|
+
};
|
|
3269
|
+
var matchCompanySkill = {
|
|
3270
|
+
name: "match-company",
|
|
3271
|
+
description: "Kick off a company-profile match (enrichment) cycle. Creates a company:match issue for an existing profile and dispatches Phase 4 (Match) in the company-profile-analyst agent. Match enriches the profile with business-model, segment, and size context from existing docs \u2014 no web searches.",
|
|
3272
|
+
disableModelInvocation: true,
|
|
3273
|
+
userInvocable: true,
|
|
3274
|
+
context: "fork",
|
|
3275
|
+
agent: "company-profile-analyst",
|
|
3276
|
+
platforms: { cursor: { exclude: true } },
|
|
3277
|
+
instructions: [
|
|
3278
|
+
"# Match Company",
|
|
3279
|
+
"",
|
|
3280
|
+
"Enrich an existing company profile against the project's",
|
|
3281
|
+
"business-model canvases, industry segments, and size descriptions.",
|
|
3282
|
+
"Creates a `company:match` issue for the target profile and",
|
|
3283
|
+
"dispatches Phase 4 (Match) in the company-profile-analyst agent.",
|
|
3284
|
+
"",
|
|
3285
|
+
"**This is enrichment of a known profile, not entity",
|
|
3286
|
+
"deduplication** \u2014 the profile already exists and must be passed by",
|
|
3287
|
+
"path.",
|
|
3288
|
+
"",
|
|
3289
|
+
"## Usage",
|
|
3290
|
+
"",
|
|
3291
|
+
"/match-company <path-to-profile>",
|
|
3292
|
+
"",
|
|
3293
|
+
"Optional extensions in the issue body:",
|
|
3294
|
+
"- `business_models_root: <path>` \u2014 override `<BUSINESS_MODELS_ROOT>`",
|
|
3295
|
+
" if the project's business-model canvases do not live at the",
|
|
3296
|
+
" default location",
|
|
3297
|
+
"- `only: <comma-separated list of segment slugs>` \u2014 match only",
|
|
3298
|
+
" against the listed segments (useful when a new canvas triggers a",
|
|
3299
|
+
" re-match)",
|
|
3300
|
+
"",
|
|
3301
|
+
"## Default Paths",
|
|
3302
|
+
"",
|
|
3303
|
+
"If the project has no override in `docs/src/content/docs/project-context.md` or",
|
|
3304
|
+
"`agentConfig.rules`, the agent reads canvases from:",
|
|
3305
|
+
"",
|
|
3306
|
+
"- `docs/src/content/docs/industry-research/`",
|
|
3307
|
+
"",
|
|
3308
|
+
"## Budget",
|
|
3309
|
+
"",
|
|
3310
|
+
"- **No web searches.** Phase 4 reads existing docs and edits the",
|
|
3311
|
+
" profile + one cross-link per matched canvas. Anything that cannot",
|
|
3312
|
+
" be decided from existing docs is flagged in the profile's",
|
|
3313
|
+
" `## Risks / Open Questions` section.",
|
|
3314
|
+
"",
|
|
3315
|
+
"## Steps",
|
|
3316
|
+
"",
|
|
3317
|
+
"1. Create a `company:match` issue with `type:company-profile`,",
|
|
3318
|
+
" `priority:medium`, and `status:ready`. Body must include the",
|
|
3319
|
+
" profile path and any overrides.",
|
|
3320
|
+
"2. Execute Phase 4 (Match) of the company-profile-analyst agent.",
|
|
3321
|
+
"",
|
|
3322
|
+
"## Output",
|
|
3323
|
+
"",
|
|
3324
|
+
"- The profile gains a `## Business Model Context` section",
|
|
3325
|
+
"- Each matched business-model canvas gains a single cross-link line",
|
|
3326
|
+
" in its Traceability / Sources section",
|
|
3327
|
+
"- The profile's `referencedIn` frontmatter is updated with matched",
|
|
3328
|
+
" paths",
|
|
3329
|
+
"- A revision-history row summarizing the matched segments"
|
|
3330
|
+
].join("\n")
|
|
3331
|
+
};
|
|
3332
|
+
var refreshCompanySkill = {
|
|
3333
|
+
name: "refresh-company",
|
|
3334
|
+
description: "Kick off a company-profile refresh cycle. Creates a company:refresh issue for an existing profile and dispatches Phase 5 (Refresh) in the company-profile-analyst agent. Refresh re-verifies the profile with 4\u20136 targeted web searches and updates it in place. Respects a configurable staleness threshold so profiles younger than the threshold exit early.",
|
|
3335
|
+
disableModelInvocation: true,
|
|
3336
|
+
userInvocable: true,
|
|
3337
|
+
context: "fork",
|
|
3338
|
+
agent: "company-profile-analyst",
|
|
3339
|
+
platforms: { cursor: { exclude: true } },
|
|
3340
|
+
instructions: [
|
|
3341
|
+
"# Refresh Company",
|
|
3342
|
+
"",
|
|
3343
|
+
"Re-verify an existing company profile with a small number of",
|
|
3344
|
+
"targeted web searches and update the profile in place. Creates a",
|
|
3345
|
+
"`company:refresh` issue for the target profile and dispatches",
|
|
3346
|
+
"Phase 5 (Refresh) in the company-profile-analyst agent.",
|
|
3347
|
+
"",
|
|
3348
|
+
"Refresh respects a configurable **staleness threshold** so scheduled",
|
|
3349
|
+
"refreshes do not burn search budget on profiles that are still",
|
|
3350
|
+
"fresh.",
|
|
3351
|
+
"",
|
|
3352
|
+
"## Usage",
|
|
3353
|
+
"",
|
|
3354
|
+
"/refresh-company <path-to-profile>",
|
|
3355
|
+
"",
|
|
3356
|
+
"Optional extensions in the issue body:",
|
|
3357
|
+
"- `refresh_days: <N>` \u2014 override the default 180-day staleness",
|
|
3358
|
+
" threshold for this run",
|
|
3359
|
+
"- `force: true` \u2014 refresh even if the profile is younger than the",
|
|
3360
|
+
" threshold",
|
|
3361
|
+
"- `retype: <taxonomy value>` \u2014 explicitly allow Phase 5 to change",
|
|
3362
|
+
" the profile's `company_type` when the refresh finds material",
|
|
3363
|
+
" evidence of a type change",
|
|
3364
|
+
"",
|
|
3365
|
+
"## Staleness Threshold",
|
|
3366
|
+
"",
|
|
3367
|
+
"Order of precedence (first match wins):",
|
|
3368
|
+
"",
|
|
3369
|
+
"1. `refresh_days` in the issue body (per-run override)",
|
|
3370
|
+
"2. `refresh_days` frontmatter on the profile itself",
|
|
3371
|
+
"3. Project-wide default declared under a `## Refresh Cadence`",
|
|
3372
|
+
" section in `docs/src/content/docs/project-context.md`",
|
|
3373
|
+
"4. Built-in default: **180 days**",
|
|
3374
|
+
"",
|
|
3375
|
+
"If the profile's `date` frontmatter plus the resolved threshold is",
|
|
3376
|
+
"in the future (i.e. the profile is still fresh) and `force: true`",
|
|
3377
|
+
"is not set, Phase 5 closes the refresh issue with a short comment",
|
|
3378
|
+
"and stops without running any searches.",
|
|
3379
|
+
"",
|
|
3380
|
+
"## Budget",
|
|
3381
|
+
"",
|
|
3382
|
+
"- **4\u20136 targeted web searches** focused on recent news, product",
|
|
3383
|
+
" launches, funding/acquisitions, leadership changes, and",
|
|
3384
|
+
" partnerships / certifications.",
|
|
3385
|
+
"",
|
|
3386
|
+
"## Steps",
|
|
3387
|
+
"",
|
|
3388
|
+
"1. Create a `company:refresh` issue with `type:company-profile`,",
|
|
3389
|
+
" `priority:medium`, and `status:ready`. Body must include the",
|
|
3390
|
+
" profile path and any overrides.",
|
|
3391
|
+
"2. Execute Phase 5 (Refresh) of the company-profile-analyst agent.",
|
|
3392
|
+
"",
|
|
3393
|
+
"## Output",
|
|
3394
|
+
"",
|
|
3395
|
+
"- The profile is updated in place (sections edited, `date` bumped,",
|
|
3396
|
+
" slug preserved)",
|
|
3397
|
+
"- A revision-history row summarizing the delta \u2014 or",
|
|
3398
|
+
" `Refreshed: no material change` when the search budget found",
|
|
3399
|
+
" nothing material",
|
|
3400
|
+
"- Reference entries updated if the company's relevance to a research",
|
|
3401
|
+
" area shifted"
|
|
3402
|
+
].join("\n")
|
|
3403
|
+
};
|
|
3404
|
+
var analyzeSegmentSkill = {
|
|
3405
|
+
name: "analyze-segment",
|
|
3406
|
+
description: "Kick off a segment-level competitive-analysis cycle. Creates a company:analyze issue for the target segment and dispatches Phase 6 (Analyze) in the company-profile-analyst agent. Analyze synthesizes every profile in the segment into one competitive-analysis document. Blocks on open company:draft issues for the segment.",
|
|
3407
|
+
disableModelInvocation: true,
|
|
3408
|
+
userInvocable: true,
|
|
3409
|
+
context: "fork",
|
|
3410
|
+
agent: "company-profile-analyst",
|
|
3411
|
+
platforms: { cursor: { exclude: true } },
|
|
3412
|
+
instructions: [
|
|
3413
|
+
"# Analyze Segment",
|
|
3414
|
+
"",
|
|
3415
|
+
"Produce a segment-level competitive analysis by synthesizing every",
|
|
3416
|
+
"company profile in the target segment into one markdown document.",
|
|
3417
|
+
"Creates a `company:analyze` issue and dispatches Phase 6 (Analyze)",
|
|
3418
|
+
"in the company-profile-analyst agent.",
|
|
3419
|
+
"",
|
|
3420
|
+
"**This is pure synthesis** \u2014 no web searches, no new profile work.",
|
|
3421
|
+
"All inputs must already exist under the profiles directory before",
|
|
3422
|
+
"you run this skill.",
|
|
3423
|
+
"",
|
|
3424
|
+
"## Usage",
|
|
3425
|
+
"",
|
|
3426
|
+
"/analyze-segment <segment-slug>",
|
|
3427
|
+
"",
|
|
3428
|
+
"Optional extensions in the issue body:",
|
|
3429
|
+
"- `profiles: <list of paths>` \u2014 explicit list of profile files to",
|
|
3430
|
+
" include; otherwise the agent discovers profiles by scanning for",
|
|
3431
|
+
" the segment slug in each profile's `referencedIn` frontmatter",
|
|
3432
|
+
"- `analysis_dir: <path>` \u2014 override `<ANALYSIS_DIR>` if the project",
|
|
3433
|
+
" stores analyses somewhere other than the default",
|
|
3434
|
+
"",
|
|
3435
|
+
"## Default Paths",
|
|
3436
|
+
"",
|
|
3437
|
+
"If the project has no override in `docs/src/content/docs/project-context.md` or",
|
|
3438
|
+
"`agentConfig.rules`, outputs land under:",
|
|
3439
|
+
"",
|
|
3440
|
+
"- `docs/companies/analysis/<segment-slug>.md`",
|
|
3441
|
+
"",
|
|
3442
|
+
"## Blocking Rule",
|
|
3443
|
+
"",
|
|
3444
|
+
"Phase 6 refuses to publish a partial landscape. If any",
|
|
3445
|
+
"`company:draft` issues whose title or body mention",
|
|
3446
|
+
"`<SEGMENT_SLUG>` are still open, the analyze issue is marked",
|
|
3447
|
+
"`status:blocked` with `Depends on: #<N>` lines pointing at each",
|
|
3448
|
+
"open draft, `status:in-progress` is removed, and Phase 6 exits",
|
|
3449
|
+
"without writing the analysis. The issue becomes eligible again",
|
|
3450
|
+
"once the drafts close.",
|
|
3451
|
+
"",
|
|
3452
|
+
"## Budget",
|
|
3453
|
+
"",
|
|
3454
|
+
"- **No web searches.** Pure synthesis from existing profiles (and",
|
|
3455
|
+
" optionally the project's own product docs).",
|
|
3456
|
+
"",
|
|
3457
|
+
"## Steps",
|
|
3458
|
+
"",
|
|
3459
|
+
"1. Create a `company:analyze` issue with `type:company-profile`,",
|
|
3460
|
+
" `priority:medium`, and `status:ready`. Body must include the",
|
|
3461
|
+
" segment slug and any overrides.",
|
|
3462
|
+
"2. Execute Phase 6 (Analyze) of the company-profile-analyst agent.",
|
|
3463
|
+
"",
|
|
3464
|
+
"## Output",
|
|
3465
|
+
"",
|
|
3466
|
+
"- One markdown document at `<ANALYSIS_DIR>/<SEGMENT_SLUG>.md`",
|
|
3467
|
+
" combining feature-comparison matrix, pricing comparison,",
|
|
3468
|
+
" positioning map, strengths & vulnerabilities, strategic",
|
|
3469
|
+
" implications, and recommended actions \u2014 every claim sourced back",
|
|
3470
|
+
" to the underlying profiles",
|
|
3471
|
+
"- This skill does **not** edit the underlying profiles. Cross-",
|
|
3472
|
+
" linking a profile back to the analysis is the job of a",
|
|
3473
|
+
" subsequent `company:match` pass."
|
|
2742
3474
|
].join("\n")
|
|
2743
3475
|
};
|
|
2744
3476
|
var companyProfileBundle = {
|
|
2745
3477
|
name: "company-profile",
|
|
2746
|
-
description: "Company research and profiling pipeline: research, draft profile, followup. Enabled by default; domain-neutral; filesystem-durable between phases. Phase 3 (Followup) hands surfaced people and software products off to the `people-profile` and `software-profile` bundles via `people:research` and `software:research` issues.",
|
|
3478
|
+
description: "Company research and profiling pipeline: research, draft profile, followup, match, refresh, analyze. Enabled by default; domain-neutral; filesystem-durable between phases. Phase 3 (Followup) hands surfaced people and software products off to the `people-profile` and `software-profile` bundles via `people:research` and `software:research` issues. Phase 4 (Match) enriches profiles against business-model canvases. Phase 5 (Refresh) re-verifies profiles on a configurable staleness cadence. Phase 6 (Analyze) synthesizes profiles in a segment into a competitive-analysis document.",
|
|
2747
3479
|
appliesWhen: () => true,
|
|
2748
3480
|
rules: [
|
|
2749
3481
|
{
|
|
2750
3482
|
name: "company-profile-workflow",
|
|
2751
|
-
description: "Describes the
|
|
3483
|
+
description: "Describes the 6-phase company-profile pipeline, the company:* label taxonomy, and the boundary against downstream research agents.",
|
|
2752
3484
|
scope: AGENT_RULE_SCOPE.ALWAYS,
|
|
2753
3485
|
content: [
|
|
2754
3486
|
"# Company Profile Workflow",
|
|
2755
3487
|
"",
|
|
2756
3488
|
"Use `/profile-company <company-name>` to kick off a company",
|
|
2757
|
-
"research and profiling pipeline. The pipeline runs in up to
|
|
2758
|
-
"phases \u2014 research, draft, followup
|
|
2759
|
-
"GitHub issue labeled `company:research`,
|
|
2760
|
-
"`company:followup
|
|
2761
|
-
"",
|
|
2762
|
-
"
|
|
2763
|
-
"
|
|
2764
|
-
"
|
|
2765
|
-
"
|
|
2766
|
-
"
|
|
3489
|
+
"research and profiling pipeline. The pipeline runs in up to 6",
|
|
3490
|
+
"phases \u2014 research, draft, followup, match, refresh, analyze \u2014",
|
|
3491
|
+
"each tracked by its own GitHub issue labeled `company:research`,",
|
|
3492
|
+
"`company:draft`, `company:followup`, `company:match`,",
|
|
3493
|
+
"`company:refresh`, or `company:analyze`. All issues carry",
|
|
3494
|
+
"`type:company-profile`.",
|
|
3495
|
+
"",
|
|
3496
|
+
"Three additional user-invocable skills drive the maintenance and",
|
|
3497
|
+
"synthesis phases independently:",
|
|
3498
|
+
"",
|
|
3499
|
+
"- `/match-company <path-to-profile>` \u2014 enrich an existing",
|
|
3500
|
+
" profile with business-model and segment context from the",
|
|
3501
|
+
" project's business-model canvases (Phase 4, no web searches).",
|
|
3502
|
+
"- `/refresh-company <path-to-profile>` \u2014 re-verify an existing",
|
|
3503
|
+
" profile with 4\u20136 targeted web searches and update it in place",
|
|
3504
|
+
" (Phase 5, respects a configurable staleness threshold).",
|
|
3505
|
+
"- `/analyze-segment <segment-slug>` \u2014 synthesize every profile",
|
|
3506
|
+
" in a segment into one competitive-analysis document (Phase 6,",
|
|
3507
|
+
" no web searches; blocks on open `company:draft` issues for",
|
|
3508
|
+
" the segment).",
|
|
3509
|
+
"",
|
|
3510
|
+
"The pipeline produces **company profiles, notes, and segment",
|
|
3511
|
+
"analyses**. Deeper research on notable people and software",
|
|
3512
|
+
"products surfaced while profiling is delegated to the",
|
|
3513
|
+
"`people-profile` and `software-profile` bundles via",
|
|
3514
|
+
"`people:research` and `software:research` issues opened during",
|
|
3515
|
+
"Phase 3 (Followup).",
|
|
2767
3516
|
"",
|
|
2768
3517
|
"See the `company-profile-analyst` agent definition for full",
|
|
2769
|
-
"workflow details, default paths, the company-type taxonomy,
|
|
2770
|
-
"phase-by-phase instructions."
|
|
3518
|
+
"workflow details, default paths, the company-type taxonomy, the",
|
|
3519
|
+
"staleness-threshold rules, and phase-by-phase instructions."
|
|
2771
3520
|
].join("\n"),
|
|
2772
3521
|
platforms: {
|
|
2773
3522
|
cursor: { exclude: true }
|
|
@@ -2775,7 +3524,12 @@ var companyProfileBundle = {
|
|
|
2775
3524
|
tags: ["workflow"]
|
|
2776
3525
|
}
|
|
2777
3526
|
],
|
|
2778
|
-
skills: [
|
|
3527
|
+
skills: [
|
|
3528
|
+
profileCompanySkill,
|
|
3529
|
+
matchCompanySkill,
|
|
3530
|
+
refreshCompanySkill,
|
|
3531
|
+
analyzeSegmentSkill
|
|
3532
|
+
],
|
|
2779
3533
|
subAgents: [companyProfileAnalystSubAgent],
|
|
2780
3534
|
labels: [
|
|
2781
3535
|
{
|
|
@@ -2797,6 +3551,21 @@ var companyProfileBundle = {
|
|
|
2797
3551
|
name: "company:followup",
|
|
2798
3552
|
color: "D4C5F9",
|
|
2799
3553
|
description: "Phase 3: enqueue follow-up research issues for people and products surfaced in the profile"
|
|
3554
|
+
},
|
|
3555
|
+
{
|
|
3556
|
+
name: "company:match",
|
|
3557
|
+
color: "FBCA04",
|
|
3558
|
+
description: "Phase 4: enrich a company profile with business-model, segment, and size context from existing docs"
|
|
3559
|
+
},
|
|
3560
|
+
{
|
|
3561
|
+
name: "company:refresh",
|
|
3562
|
+
color: "F9D0C4",
|
|
3563
|
+
description: "Phase 5: re-verify an existing company profile with targeted web searches and update it in place"
|
|
3564
|
+
},
|
|
3565
|
+
{
|
|
3566
|
+
name: "company:analyze",
|
|
3567
|
+
color: "5319E7",
|
|
3568
|
+
description: "Phase 6: synthesize every company profile in a segment into a competitive-analysis document"
|
|
2800
3569
|
}
|
|
2801
3570
|
]
|
|
2802
3571
|
};
|
|
@@ -14488,6 +15257,141 @@ var vitestBundle = {
|
|
|
14488
15257
|
}
|
|
14489
15258
|
};
|
|
14490
15259
|
|
|
15260
|
+
// src/agent/bundles/features.ts
|
|
15261
|
+
var SOURCE_TIER_HEADINGS = [
|
|
15262
|
+
{ key: "t1", heading: "### T1 \u2014 Primary Living" },
|
|
15263
|
+
{ key: "t2", heading: "### T2 \u2014 Primary Snapshot" },
|
|
15264
|
+
{ key: "t3", heading: "### T3 \u2014 Secondary" },
|
|
15265
|
+
{ key: "t4", heading: "### T4 \u2014 Self-Reported / Marketing" }
|
|
15266
|
+
];
|
|
15267
|
+
function renderSourceTierExamples(content, examples) {
|
|
15268
|
+
if (!examples) {
|
|
15269
|
+
return content;
|
|
15270
|
+
}
|
|
15271
|
+
const tierEntries = SOURCE_TIER_HEADINGS.flatMap(({ key, heading }) => {
|
|
15272
|
+
const list = examples[key];
|
|
15273
|
+
if (!list || list.length === 0) {
|
|
15274
|
+
return [];
|
|
15275
|
+
}
|
|
15276
|
+
return [{ heading, list }];
|
|
15277
|
+
});
|
|
15278
|
+
if (tierEntries.length === 0) {
|
|
15279
|
+
return content;
|
|
15280
|
+
}
|
|
15281
|
+
let updated = content;
|
|
15282
|
+
for (const { heading, list } of tierEntries) {
|
|
15283
|
+
const injection = [
|
|
15284
|
+
"",
|
|
15285
|
+
"**Project-specific examples:**",
|
|
15286
|
+
"",
|
|
15287
|
+
...list.map((ex) => `- ${ex}`)
|
|
15288
|
+
].join("\n");
|
|
15289
|
+
updated = insertAfterHeadingBlock(updated, heading, injection);
|
|
15290
|
+
}
|
|
15291
|
+
return updated;
|
|
15292
|
+
}
|
|
15293
|
+
function renderCustomDocSections(bundle, sections) {
|
|
15294
|
+
const matching = sections.filter((s) => s.bundleName === bundle.name);
|
|
15295
|
+
if (matching.length === 0) {
|
|
15296
|
+
return bundle;
|
|
15297
|
+
}
|
|
15298
|
+
let rules = bundle.rules;
|
|
15299
|
+
const currentAnchorByTarget = /* @__PURE__ */ new Map();
|
|
15300
|
+
for (const section of matching) {
|
|
15301
|
+
const injection = renderCustomDocSectionBlock(section);
|
|
15302
|
+
const seededAnchor = currentAnchorByTarget.get(section.afterSection);
|
|
15303
|
+
let targetIndex = -1;
|
|
15304
|
+
let targetHeading = "";
|
|
15305
|
+
for (let i = 0; i < rules.length; i += 1) {
|
|
15306
|
+
if (seededAnchor && rules[i].content.includes(seededAnchor)) {
|
|
15307
|
+
targetIndex = i;
|
|
15308
|
+
targetHeading = seededAnchor;
|
|
15309
|
+
break;
|
|
15310
|
+
}
|
|
15311
|
+
if (!seededAnchor) {
|
|
15312
|
+
const match = findHeadingForTitle(
|
|
15313
|
+
rules[i].content,
|
|
15314
|
+
section.afterSection
|
|
15315
|
+
);
|
|
15316
|
+
if (match) {
|
|
15317
|
+
targetIndex = i;
|
|
15318
|
+
targetHeading = match;
|
|
15319
|
+
break;
|
|
15320
|
+
}
|
|
15321
|
+
}
|
|
15322
|
+
}
|
|
15323
|
+
if (targetIndex === -1) {
|
|
15324
|
+
continue;
|
|
15325
|
+
}
|
|
15326
|
+
const targetRule = rules[targetIndex];
|
|
15327
|
+
const updatedRule = {
|
|
15328
|
+
...targetRule,
|
|
15329
|
+
content: insertAfterHeadingBlock(
|
|
15330
|
+
targetRule.content,
|
|
15331
|
+
targetHeading,
|
|
15332
|
+
injection
|
|
15333
|
+
)
|
|
15334
|
+
};
|
|
15335
|
+
rules = [
|
|
15336
|
+
...rules.slice(0, targetIndex),
|
|
15337
|
+
updatedRule,
|
|
15338
|
+
...rules.slice(targetIndex + 1)
|
|
15339
|
+
];
|
|
15340
|
+
currentAnchorByTarget.set(
|
|
15341
|
+
section.afterSection,
|
|
15342
|
+
`## ${section.sectionTitle}`
|
|
15343
|
+
);
|
|
15344
|
+
}
|
|
15345
|
+
if (rules === bundle.rules) {
|
|
15346
|
+
return bundle;
|
|
15347
|
+
}
|
|
15348
|
+
return { ...bundle, rules };
|
|
15349
|
+
}
|
|
15350
|
+
function renderCustomDocSectionBlock(section) {
|
|
15351
|
+
const body = section.body.replace(/[\r\n]+$/u, "");
|
|
15352
|
+
return ["", `## ${section.sectionTitle}`, "", body].join("\n");
|
|
15353
|
+
}
|
|
15354
|
+
function findHeadingForTitle(content, title) {
|
|
15355
|
+
const lines = content.split("\n");
|
|
15356
|
+
for (const line of lines) {
|
|
15357
|
+
const match = line.match(/^(#{1,6}) (.+)$/u);
|
|
15358
|
+
if (match && match[2] === title) {
|
|
15359
|
+
return line;
|
|
15360
|
+
}
|
|
15361
|
+
}
|
|
15362
|
+
return void 0;
|
|
15363
|
+
}
|
|
15364
|
+
function insertAfterHeadingBlock(content, heading, injection) {
|
|
15365
|
+
const lines = content.split("\n");
|
|
15366
|
+
const headingIndex = lines.findIndex((line) => line === heading);
|
|
15367
|
+
if (headingIndex === -1) {
|
|
15368
|
+
return content;
|
|
15369
|
+
}
|
|
15370
|
+
const headingLevel = countLeadingHashes(heading);
|
|
15371
|
+
let endIndex = lines.length - 1;
|
|
15372
|
+
for (let i = headingIndex + 1; i < lines.length; i += 1) {
|
|
15373
|
+
const nextLevel = countLeadingHashes(lines[i]);
|
|
15374
|
+
if (nextLevel > 0 && nextLevel <= headingLevel) {
|
|
15375
|
+
endIndex = i - 1;
|
|
15376
|
+
break;
|
|
15377
|
+
}
|
|
15378
|
+
}
|
|
15379
|
+
while (endIndex > headingIndex && lines[endIndex] === "") {
|
|
15380
|
+
endIndex -= 1;
|
|
15381
|
+
}
|
|
15382
|
+
const injectionLines = injection.split("\n");
|
|
15383
|
+
const next = [
|
|
15384
|
+
...lines.slice(0, endIndex + 1),
|
|
15385
|
+
...injectionLines,
|
|
15386
|
+
...lines.slice(endIndex + 1)
|
|
15387
|
+
];
|
|
15388
|
+
return next.join("\n");
|
|
15389
|
+
}
|
|
15390
|
+
function countLeadingHashes(line) {
|
|
15391
|
+
const match = line.match(/^(#{1,6}) /u);
|
|
15392
|
+
return match ? match[1].length : 0;
|
|
15393
|
+
}
|
|
15394
|
+
|
|
14491
15395
|
// src/agent/bundles/focus.ts
|
|
14492
15396
|
var DEFAULT_FOCUS_FILE_PATH = ".claude/focus.json";
|
|
14493
15397
|
var DEFAULT_SCHEMA_VERSION = 1;
|
|
@@ -15458,6 +16362,19 @@ var AgentConfig = class _AgentConfig extends Component8 {
|
|
|
15458
16362
|
const isAgentConfig = (c) => c instanceof _AgentConfig;
|
|
15459
16363
|
return project.components.find(isAgentConfig);
|
|
15460
16364
|
}
|
|
16365
|
+
/**
|
|
16366
|
+
* Returns `true` when at least one tier array on the supplied
|
|
16367
|
+
* `SourceTierExamples` is non-empty, signalling that the consuming
|
|
16368
|
+
* repo has opted into rendering the base bundle's
|
|
16369
|
+
* `source-quality-verification` rule. Returns `false` for
|
|
16370
|
+
* `undefined`, `{}`, or a fully-empty `{ t1: [], t2: [], t3: [], t4: [] }`.
|
|
16371
|
+
*/
|
|
16372
|
+
static hasActiveTierExamples(examples) {
|
|
16373
|
+
if (!examples) {
|
|
16374
|
+
return false;
|
|
16375
|
+
}
|
|
16376
|
+
return (examples.t1?.length ?? 0) > 0 || (examples.t2?.length ?? 0) > 0 || (examples.t3?.length ?? 0) > 0 || (examples.t4?.length ?? 0) > 0;
|
|
16377
|
+
}
|
|
15461
16378
|
/**
|
|
15462
16379
|
* Merges default Claude permissions with bundle and user-supplied settings.
|
|
15463
16380
|
*
|
|
@@ -15677,6 +16594,24 @@ ${section}`
|
|
|
15677
16594
|
}
|
|
15678
16595
|
}
|
|
15679
16596
|
}
|
|
16597
|
+
const tierExamples = this.options.features?.sourceTierExamples;
|
|
16598
|
+
if (_AgentConfig.hasActiveTierExamples(tierExamples)) {
|
|
16599
|
+
const sourceRule = ruleMap.get("source-quality-verification");
|
|
16600
|
+
if (sourceRule) {
|
|
16601
|
+
const updated = renderSourceTierExamples(
|
|
16602
|
+
sourceRule.content,
|
|
16603
|
+
tierExamples
|
|
16604
|
+
);
|
|
16605
|
+
if (updated !== sourceRule.content) {
|
|
16606
|
+
ruleMap.set("source-quality-verification", {
|
|
16607
|
+
...sourceRule,
|
|
16608
|
+
content: updated
|
|
16609
|
+
});
|
|
16610
|
+
}
|
|
16611
|
+
}
|
|
16612
|
+
} else {
|
|
16613
|
+
ruleMap.delete("source-quality-verification");
|
|
16614
|
+
}
|
|
15680
16615
|
return [...ruleMap.values()].sort((a, b) => {
|
|
15681
16616
|
if (a.name === "project-overview") return -1;
|
|
15682
16617
|
if (b.name === "project-overview") return 1;
|
|
@@ -15689,19 +16624,24 @@ ${section}`
|
|
|
15689
16624
|
/**
|
|
15690
16625
|
* Return a bundle's rules with `filePatterns` narrowed to the projects
|
|
15691
16626
|
* that actually matched the bundle's detection predicate (when the bundle
|
|
15692
|
-
* provides `findApplicableProjects`)
|
|
15693
|
-
*
|
|
16627
|
+
* provides `findApplicableProjects`) and any project-specified
|
|
16628
|
+
* `features.customDocSections` entries injected into the matching rule
|
|
16629
|
+
* content. Rules with `ALWAYS` scope and rules on bundles that don't
|
|
16630
|
+
* implement the hook are returned with only the custom-section
|
|
16631
|
+
* transformation (if any) applied.
|
|
15694
16632
|
*/
|
|
15695
16633
|
bundleRulesFor(bundle) {
|
|
15696
|
-
|
|
15697
|
-
|
|
16634
|
+
const customSections = this.options.features?.customDocSections ?? [];
|
|
16635
|
+
const withCustomSections = customSections.length > 0 ? renderCustomDocSections(bundle, customSections) : bundle;
|
|
16636
|
+
if (!withCustomSections.findApplicableProjects) {
|
|
16637
|
+
return withCustomSections.rules;
|
|
15698
16638
|
}
|
|
15699
|
-
const detected =
|
|
16639
|
+
const detected = withCustomSections.findApplicableProjects(this.project);
|
|
15700
16640
|
if (detected.length === 0) {
|
|
15701
|
-
return
|
|
16641
|
+
return withCustomSections.rules;
|
|
15702
16642
|
}
|
|
15703
16643
|
const scoped = scopeFilePatternsToProjects(this.project, detected);
|
|
15704
|
-
return
|
|
16644
|
+
return withCustomSections.rules.map(
|
|
15705
16645
|
(rule) => rule.scope === AGENT_RULE_SCOPE.FILE_PATTERN ? { ...rule, filePatterns: scoped } : rule
|
|
15706
16646
|
);
|
|
15707
16647
|
}
|
|
@@ -18500,9 +19440,12 @@ export {
|
|
|
18500
19440
|
pnpmBundle,
|
|
18501
19441
|
prReviewBundle,
|
|
18502
19442
|
projenBundle,
|
|
19443
|
+
renderCustomDocSectionBlock,
|
|
19444
|
+
renderCustomDocSections,
|
|
18503
19445
|
renderFocusSection,
|
|
18504
19446
|
renderMeetingTypesSection,
|
|
18505
19447
|
renderPriorityRulesSection,
|
|
19448
|
+
renderSourceTierExamples,
|
|
18506
19449
|
requirementsAnalystBundle,
|
|
18507
19450
|
requirementsReviewerBundle,
|
|
18508
19451
|
requirementsWriterBundle,
|