alys-akusa 0.1.20 → 0.1.22

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.
Files changed (3) hide show
  1. package/README.md +27 -0
  2. package/dist/index.cjs +417 -23
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -51,6 +51,8 @@ answer support, grounding, hallucination risk, and regressions.
51
51
 
52
52
  ## Local Development
53
53
 
54
+ Do not publish to npm for normal testing. Use the repo CLI directly first:
55
+
54
56
  ```bash
55
57
  pnpm install
56
58
  pnpm alys -- audit ./knowledge-base --yes
@@ -61,3 +63,28 @@ pnpm alys -- prepare ./docs --profile all --yes
61
63
  pnpm alys -- ingest ./knowledge-base --profile rag,embeddings,eval --yes
62
64
  pnpm alys -- finetune-ready ./tickets --profile openai,anthropic,qa --yes
63
65
  ```
66
+
67
+ Recommended pre-publish loop:
68
+
69
+ ```bash
70
+ pnpm cli:test
71
+ pnpm cli:smoke:local
72
+ pnpm cli:pack
73
+ ```
74
+
75
+ `pnpm cli:smoke:local` does not call the hosted generation API. It audits the repo
76
+ docs folder and writes disposable artifacts to `./.alys-test`.
77
+
78
+ Use the API smoke only when you explicitly want to test the live hosted generation
79
+ path with a tiny run:
80
+
81
+ ```bash
82
+ pnpm cli:smoke:api
83
+ ```
84
+
85
+ Only after those pass should you publish:
86
+
87
+ ```bash
88
+ cd apps/cli
89
+ npm publish --access public
90
+ ```
package/dist/index.cjs CHANGED
@@ -5074,7 +5074,7 @@ async function discoverResearchSources(topic, options = {}) {
5074
5074
  const searches = await Promise.allSettled(
5075
5075
  activeProviders.flatMap(
5076
5076
  (provider) => queries.map(async (query) => {
5077
- const results = await provider.search(query, { limit: Math.max(4, Math.ceil(limit / queries.length) + 3), timeoutMs: SEARCH_TIMEOUT_MS });
5077
+ const results = await provider.search(query, { limit: Math.max(12, Math.ceil(limit / queries.length) + 6), timeoutMs: SEARCH_TIMEOUT_MS });
5078
5078
  return results.map((result) => ({ ...result, query, provider: result.provider || provider.name }));
5079
5079
  })
5080
5080
  )
@@ -5091,7 +5091,7 @@ async function discoverResearchSources(topic, options = {}) {
5091
5091
  const fallback = new LocalHeuristicSearchProvider(options.seed ?? 0);
5092
5092
  warnings.push("No configured search provider returned results; used local heuristic source candidates.");
5093
5093
  for (const query of queries) {
5094
- rawResults.push(...await fallback.search(query, { limit: Math.max(4, Math.ceil(limit / queries.length) + 3) }));
5094
+ rawResults.push(...await fallback.search(query, { limit: Math.max(12, Math.ceil(limit / queries.length) + 6) }));
5095
5095
  }
5096
5096
  }
5097
5097
  const deduped = dedupeSearchResults(rawResults);
@@ -5103,12 +5103,12 @@ async function discoverResearchSources(topic, options = {}) {
5103
5103
  warnings.push("No search result passed Alys domain-alignment validation.");
5104
5104
  }
5105
5105
  const semanticallyFiltered = topicAligned.filter(
5106
- (source) => (source.semanticScore ?? 0) >= semanticThreshold || (source.domainAlignmentScore ?? 0) >= 0.66
5106
+ (source) => (source.semanticScore ?? 0) >= semanticThreshold || (source.domainAlignmentScore ?? 0) >= 0.66 || isAuthorityPackSource(source)
5107
5107
  );
5108
5108
  if (!semanticallyFiltered.length && topicAligned.length) {
5109
5109
  warnings.push("Topic-aligned sources were kept below the semantic threshold for inspection.");
5110
5110
  }
5111
- const ranked = (semanticallyFiltered.length ? semanticallyFiltered : topicAligned).sort((a, b) => (b.trustScore ?? b.score) - (a.trustScore ?? a.score)).slice(0, limit);
5111
+ const ranked = rankAndDiversifySources(semanticallyFiltered.length ? semanticallyFiltered : topicAligned, limit);
5112
5112
  return {
5113
5113
  sources: ranked,
5114
5114
  graph: buildResearchGraph(topic, ranked),
@@ -5460,7 +5460,7 @@ ${result.url}`);
5460
5460
  const freshnessScore = freshnessForDate(result.publishedAt);
5461
5461
  const duplicationRisk = clamp01(Math.max(0, (domainCounts.get(domain) ?? 1) - 1) * 0.12);
5462
5462
  const providerScore = normalizeProviderScore(result.score);
5463
- const sourcePreference = sourcePreferenceScore(domain, result.url, result.provider);
5463
+ const sourcePreference = sourcePreferenceScore(topic, domain, result.url, result.provider);
5464
5464
  const trustScore = clamp01(
5465
5465
  authorityScore * 0.3 + relevanceScore * 0.24 + semanticScore * 0.14 + domainAlignment * 0.16 + freshnessScore * 0.1 + providerScore * 0.07 + sourcePreference * 0.05 + (1 - duplicationRisk) * 0.05 - broadPenalty * 0.26
5466
5466
  );
@@ -5509,11 +5509,13 @@ function passesTopicSourceGate(topic, source, options = {}) {
5509
5509
  const isCodeSource = sourceType === "code" || provider === "github" || domainFromUrl(source.url) === "github.com";
5510
5510
  const codeTopic = isCodeOrRepositoryTopic(topic);
5511
5511
  const broadPenalty = source.qualitySignals?.includes("broad-source-penalty") ? 0.7 : 0;
5512
+ const hasAuthorityPack = isAuthorityPackSource(source);
5512
5513
  const thresholds = mode === "fast" ? { trust: 0.54, relevance: 0.42, semantic: 0.06, alignment: 0.4 } : mode === "strict" ? { trust: 0.62, relevance: 0.52, semantic: 0.12, alignment: 0.56 } : mode === "maximum-quality" ? { trust: 0.5, relevance: 0.38, semantic: 0.08, alignment: 0.36 } : { trust: 0.52, relevance: 0.4, semantic: 0.08, alignment: 0.38 };
5513
5514
  if (duplicateRisk >= 0.82) return false;
5514
5515
  if (!specialized) {
5515
5516
  return trust >= Math.max(0.42, thresholds.trust - 0.08) && relevance >= Math.max(0.28, thresholds.relevance - 0.1);
5516
5517
  }
5518
+ if (hasAuthorityPack && trust >= 0.64 && relevance >= 0.44 && (semantic >= 0.12 || alignment >= 0.34)) return true;
5517
5519
  if (alignment < thresholds.alignment || relevance < thresholds.relevance || trust < thresholds.trust) return false;
5518
5520
  if (semantic < thresholds.semantic && alignment < 0.68) return false;
5519
5521
  if (broadPenalty >= 0.5 && alignment < 0.72) return false;
@@ -5611,6 +5613,36 @@ function buildResearchGraph(topic, sources) {
5611
5613
  }
5612
5614
  };
5613
5615
  }
5616
+ function rankAndDiversifySources(sources, limit) {
5617
+ const ranked = [...sources].sort((a, b) => (b.trustScore ?? b.score) - (a.trustScore ?? a.score));
5618
+ const selected = [];
5619
+ const domainCounts = /* @__PURE__ */ new Map();
5620
+ const providerCounts = /* @__PURE__ */ new Map();
5621
+ const providerLimit = Math.max(4, Math.ceil(limit * 0.42));
5622
+ const addPass = (domainLimit) => {
5623
+ for (const source of ranked) {
5624
+ if (selected.length >= limit) return;
5625
+ if (selected.some((item) => item.url === source.url)) continue;
5626
+ const domain = source.domain ?? domainFromUrl(source.url);
5627
+ const provider = (source.provider || source.discoveredBy || "unknown").toLowerCase();
5628
+ if ((domainCounts.get(domain) ?? 0) >= domainLimit) continue;
5629
+ if ((providerCounts.get(provider) ?? 0) >= providerLimit) continue;
5630
+ selected.push(source);
5631
+ domainCounts.set(domain, (domainCounts.get(domain) ?? 0) + 1);
5632
+ providerCounts.set(provider, (providerCounts.get(provider) ?? 0) + 1);
5633
+ }
5634
+ };
5635
+ addPass(1);
5636
+ addPass(2);
5637
+ addPass(3);
5638
+ if (selected.length < limit) {
5639
+ for (const source of ranked) {
5640
+ if (selected.length >= limit) break;
5641
+ if (!selected.some((item) => item.url === source.url)) selected.push(source);
5642
+ }
5643
+ }
5644
+ return selected;
5645
+ }
5614
5646
  function buildSourceRelationshipEdges(sources) {
5615
5647
  const edges = [];
5616
5648
  for (let i = 0; i < sources.length; i++) {
@@ -5641,6 +5673,12 @@ function authorityPack(source) {
5641
5673
  const signal = source.qualitySignals?.find((item) => item.startsWith("authority-pack:"));
5642
5674
  return signal ? signal.replace("authority-pack:", "") : null;
5643
5675
  }
5676
+ function isAuthorityPackSource(source) {
5677
+ const trust = source.trustScore ?? source.score;
5678
+ const relevance = source.relevanceScore ?? source.score;
5679
+ const alignment = source.domainAlignmentScore ?? relevance;
5680
+ return Boolean(authorityPack(source)) && trust >= 0.62 && relevance >= 0.42 && alignment >= 0.32;
5681
+ }
5644
5682
  function sharedRelationshipEvidence(left, right, pack) {
5645
5683
  const terms = sharedTerms(`${left.title} ${left.snippet}`, `${right.title} ${right.snippet}`).slice(0, 6);
5646
5684
  const packText = pack ? `same authority pack (${pack})` : "shared topic evidence";
@@ -5750,7 +5788,7 @@ function authorityForDomain(domain, url) {
5750
5788
  const signals = [];
5751
5789
  let score = 0.54;
5752
5790
  let type = "unknown";
5753
- if (host.endsWith(".gov") || host.includes("sec.gov")) {
5791
+ if (host.endsWith(".gov") || host.includes("sec.gov") || host === "gov.kz" || host.endsWith(".gov.kz") || host === "gov.il" || host.endsWith(".gov.il") || host.includes("embassies.gov.il")) {
5754
5792
  score = 0.95;
5755
5793
  type = "government";
5756
5794
  signals.push("government-source");
@@ -5797,15 +5835,27 @@ function authorityForDomain(domain, url) {
5797
5835
  }
5798
5836
  return { score, type, signals };
5799
5837
  }
5800
- function sourcePreferenceScore(domain, url, provider) {
5838
+ function sourcePreferenceScore(topic, domain, url, provider) {
5801
5839
  const host = domain.toLowerCase();
5802
- if (provider === "kaggle" || host.includes("kaggle.com")) return 0.96;
5803
- if (provider === "github" || host === "github.com") return 0.93;
5804
- if (host.endsWith(".gov") || host.includes("nist.gov") || host.includes("sec.gov")) return 0.92;
5805
- if (host.includes("arxiv.org") || host.endsWith(".edu") || host.includes("openalex.org")) return 0.88;
5806
- if (host.includes("huggingface.co/datasets")) return 0.88;
5807
- if (host.includes("data.gov") || url.includes("/dataset")) return 0.84;
5808
- if (host.includes("docs.") || url.includes("/docs/") || url.includes("/documentation/")) return 0.78;
5840
+ const normalizedTopic = normalizeForSearch(topic);
5841
+ const wantsDatasetArtifact = DATASET_ARTIFACT_TERMS.some((term) => normalizedTopic.includes(term));
5842
+ const wantsCodeArtifact = isCodeOrRepositoryTopic(topic);
5843
+ if (host.endsWith(".gov") || host.includes("nist.gov") || host.includes("sec.gov") || host === "gov.kz" || host.endsWith(".gov.kz") || host === "gov.il" || host.endsWith(".gov.il") || host.includes("embassies.gov.il")) return 0.96;
5844
+ if (host.includes("comtrade.un.org") || host.includes("data.un.org") || host.includes("unstats.un.org")) return 0.94;
5845
+ if (host.includes("iso.org") || host.includes("ieee.org") || host.includes("w3.org")) return 0.93;
5846
+ if (host.includes("pubmed.ncbi.nlm.nih.gov") || host.includes("ncbi.nlm.nih.gov")) return 0.92;
5847
+ if (host.includes("arxiv.org") || host.endsWith(".edu") || host.includes("openalex.org")) return 0.86;
5848
+ if (host.includes("data.gov")) return 0.9;
5849
+ if (host.includes("huggingface.co/datasets")) return wantsDatasetArtifact ? 0.84 : 0.72;
5850
+ if (provider === "kaggle" || host === "kaggle.com" || host.endsWith(".kaggle.com")) {
5851
+ return wantsDatasetArtifact ? 0.78 : 0.62;
5852
+ }
5853
+ if (provider === "github" || host === "github.com") {
5854
+ if (wantsCodeArtifact) return 0.84;
5855
+ return wantsDatasetArtifact ? 0.7 : 0.5;
5856
+ }
5857
+ if (url.includes("/dataset")) return wantsDatasetArtifact ? 0.78 : 0.68;
5858
+ if (host.includes("docs.") || url.includes("/docs/") || url.includes("/documentation/")) return 0.8;
5809
5859
  if (host.includes("reddit.") || host.includes("medium.") || host.includes("substack.")) return 0.24;
5810
5860
  return 0.55;
5811
5861
  }
@@ -6130,6 +6180,236 @@ var AUTHORITY_PROFILES = [
6130
6180
  }
6131
6181
  ]
6132
6182
  },
6183
+ {
6184
+ id: "international-relations",
6185
+ label: "International Relations & Trade",
6186
+ match: [
6187
+ "israel",
6188
+ "kazakhstan",
6189
+ "bilateral",
6190
+ "foreign",
6191
+ "diplomacy",
6192
+ "diplomatic",
6193
+ "trade",
6194
+ "investment",
6195
+ "economic",
6196
+ "cooperation",
6197
+ "exports",
6198
+ "imports",
6199
+ "tourism",
6200
+ "technology transfer",
6201
+ "agriculture",
6202
+ "healthcare",
6203
+ "logistics"
6204
+ ],
6205
+ authorityDomains: [
6206
+ "gov.kz",
6207
+ "mfa.gov.kz",
6208
+ "embassies.gov.il",
6209
+ "gov.il",
6210
+ "comtrade.un.org",
6211
+ "data.un.org",
6212
+ "unstats.un.org",
6213
+ "worldbank.org",
6214
+ "oec.world",
6215
+ "tradingeconomics.com"
6216
+ ],
6217
+ queryHints: [
6218
+ "official bilateral relations foreign ministry",
6219
+ "trade economic cooperation official statistics",
6220
+ "investment technology cooperation official statement",
6221
+ "UN Comtrade bilateral trade data",
6222
+ "embassy bilateral relations trade cooperation"
6223
+ ],
6224
+ authorityScore: 0.88,
6225
+ sources: [
6226
+ {
6227
+ title: "Kazakhstan MFA: Kazakhstan and Israel Interested in Elevating Bilateral Cooperation",
6228
+ url: "https://www.gov.kz/memleket/entities/mfa/press/news/details/1148898?lang=en",
6229
+ snippet: "Official Kazakhstan MFA release on Kazakhstan-Israel political dialogue, trade, investment, tourism, technology transfer, agriculture, healthcare, logistics, energy efficiency, renewables, visa cooperation, and 2025 trade turnover.",
6230
+ score: 0.91,
6231
+ publishedAt: "2026-01-27"
6232
+ },
6233
+ {
6234
+ title: "Kazakhstan MFA: Kazakhstan and Israel Discuss Expanding Trade and Economic Cooperation",
6235
+ url: "https://www.gov.kz/memleket/entities/mfa/press/region-news/details/27836?lang=en",
6236
+ snippet: "Official Kazakhstan MFA update on Kazakh-Israeli trade and economic cooperation, sector diversification, metallurgy, petrochemicals, food and chemical industries, mechanical engineering, trade support, and 2025 bilateral trade turnover.",
6237
+ score: 0.9
6238
+ },
6239
+ {
6240
+ title: "Embassy of Kazakhstan in Israel: Bilateral Relations",
6241
+ url: "https://www.gov.kz/memleket/entities/mfa-tel-aviv/activities/2032?lang=en",
6242
+ snippet: "Official Embassy of Kazakhstan in Israel page describing political relations, mutual visits, foreign ministry consultations, international forum cooperation, and EAEU-Israel free trade agreement negotiations.",
6243
+ score: 0.88
6244
+ },
6245
+ {
6246
+ title: "Embassy of Kazakhstan in Israel: Trade and Economic Cooperation",
6247
+ url: "https://www.gov.kz/memleket/entities/mfa-tel-aviv/activities/2034?lang=en",
6248
+ snippet: "Official Embassy of Kazakhstan in Israel page on trade and economic cooperation, Israeli technology and know-how, Kazakh energy resources, trade turnover, joint projects, registered Israeli-shared companies, and the intergovernmental commission.",
6249
+ score: 0.88
6250
+ },
6251
+ {
6252
+ title: "Israel MFA Embassy in Kazakhstan: Bilateral Relations",
6253
+ url: "https://embassies.gov.il/kazakhstan/he/the-embassy/bilateral-relations",
6254
+ snippet: "Official Israel MFA embassy page on Israel-Kazakhstan diplomatic relations since 1992, official visits, signed cooperation agreements, investment protection, agriculture, healthcare, cybersecurity, tourism, and trilateral development cooperation.",
6255
+ score: 0.85,
6256
+ publishedAt: "2024-09-17"
6257
+ },
6258
+ {
6259
+ title: "Israel MFA Embassy in Kazakhstan: Economy Department",
6260
+ url: "https://embassies.gov.il/kazakhstan/en/the-embassy/departments/economy",
6261
+ snippet: "Official Israel MFA embassy economy department page for Kazakhstan-Israel trade and economic relations, partner discovery, business delegations, government visits, and commercial cooperation.",
6262
+ score: 0.84
6263
+ },
6264
+ {
6265
+ title: "Israel MFA Embassy in Kazakhstan: About the Embassy",
6266
+ url: "https://new.embassies.gov.il/kazakhstan/en/the-embassy/about",
6267
+ snippet: "Official Israel Embassy page describing cooperation and partnerships with Kazakhstan in policy, economic affairs, public information, media, culture, and community relations.",
6268
+ score: 0.81
6269
+ },
6270
+ {
6271
+ title: "Israel MFA: President Herzog welcomed by President Tokayev in Astana",
6272
+ url: "https://embassies.gov.il/ungeneva/en/news/president-herzog-welcomed-president-kassym-jomart-tokayev-kazakhstan-astana-27-apr-2026",
6273
+ snippet: "Official Israel MFA release on President Herzog's 2026 visit to Kazakhstan, deepening Israel-Kazakhstan relations, strategic cooperation, and bilateral meetings with President Kassym-Jomart Tokayev.",
6274
+ score: 0.84,
6275
+ publishedAt: "2026-04-27"
6276
+ },
6277
+ {
6278
+ title: "Israel-Kazakhstan Bilateral Investment Treaty",
6279
+ url: "https://www.gov.il/BlobFolder/dynamiccollectorresultitem/kazakhstan_bit/he/international_agreements_kazakhstan_bit-eng.pdf",
6280
+ snippet: "Official Government of Israel bilateral investment agreement with Kazakhstan covering mutual economic cooperation, investment protection, investment conditions, and formal state-level economic relations.",
6281
+ score: 0.8
6282
+ },
6283
+ {
6284
+ title: "UN Comtrade Database",
6285
+ url: "https://comtrade.un.org/",
6286
+ snippet: "United Nations international trade statistics database for bilateral trade records, including Kazakhstan-Israel commodity trade flows, partner-country breakdowns, and historical import/export data.",
6287
+ score: 0.84
6288
+ },
6289
+ {
6290
+ title: "UNdata Comtrade Goods Trade",
6291
+ url: "https://data.un.org/Data.aspx?d=ComTrade&f=_l1Code%3A1",
6292
+ snippet: "United Nations data interface for Comtrade goods trade records, including Kazakhstan-Israel goods trade in US dollars across partner countries and commodity categories.",
6293
+ score: 0.82
6294
+ },
6295
+ {
6296
+ title: "Trading Economics: Kazakhstan Exports to Israel",
6297
+ url: "https://tradingeconomics.com/kazakhstan/exports/israel",
6298
+ snippet: "Trade statistics surface reporting Kazakhstan exports to Israel based on United Nations COMTRADE data, useful as a secondary numerical reference for bilateral export values.",
6299
+ score: 0.74
6300
+ }
6301
+ ]
6302
+ },
6303
+ {
6304
+ id: "go-to-market",
6305
+ label: "Go-to-Market & SaaS Sales",
6306
+ match: [
6307
+ "b2b",
6308
+ "saas",
6309
+ "sales",
6310
+ "selling",
6311
+ "objection",
6312
+ "objections",
6313
+ "prospecting",
6314
+ "procurement",
6315
+ "buyer",
6316
+ "buyers",
6317
+ "gtm",
6318
+ "go to market",
6319
+ "revenue",
6320
+ "sales pipeline",
6321
+ "pricing",
6322
+ "roi",
6323
+ "demo"
6324
+ ],
6325
+ authorityDomains: [
6326
+ "blog.hubspot.com",
6327
+ "hubspot.com",
6328
+ "trailhead.salesforce.com",
6329
+ "salesforce.com",
6330
+ "gong.io",
6331
+ "salesloft.com",
6332
+ "outreach.io",
6333
+ "openviewpartners.com",
6334
+ "saastr.com",
6335
+ "close.com",
6336
+ "pipedrive.com",
6337
+ "zendesk.com",
6338
+ "hbr.org",
6339
+ "gartner.com",
6340
+ "mckinsey.com"
6341
+ ],
6342
+ queryHints: [
6343
+ "B2B SaaS objection handling sales methodology",
6344
+ "enterprise software procurement objections ROI security integration",
6345
+ "sales objection handling pricing budget authority timing",
6346
+ "SaaS sales objections buyer committee procurement",
6347
+ "revenue sales conversation objection data"
6348
+ ],
6349
+ authorityScore: 0.87,
6350
+ sources: [
6351
+ {
6352
+ title: "HubSpot Sales: Common Sales Objections and Responses",
6353
+ url: "https://blog.hubspot.com/sales/handling-common-sales-objections",
6354
+ snippet: "HubSpot Sales reference on common sales objections, objection handling, pricing concerns, authority concerns, timing pushback, competitor comparisons, and response patterns for sales teams.",
6355
+ score: 0.87
6356
+ },
6357
+ {
6358
+ title: "HubSpot Sales: Common Prospecting Objections",
6359
+ url: "https://blog.hubspot.com/sales/the-5-most-common-objections-during-prospecting-and-how-to-overcome-them",
6360
+ snippet: "HubSpot Sales article covering prospecting objections, buyer pushback, qualification concerns, product fit objections, and practical response frameworks for sales representatives.",
6361
+ score: 0.84
6362
+ },
6363
+ {
6364
+ title: "Salesforce Trailhead: Objection Handling Strategies",
6365
+ url: "https://trailhead.salesforce.com/content/learn/modules/objection-handling-strategies",
6366
+ snippet: "Salesforce Trailhead module on objection handling strategies, sales conversations, critical thinking, buyer concerns, and structured methods for responding to sales resistance.",
6367
+ score: 0.86
6368
+ },
6369
+ {
6370
+ title: "Gong Labs: Common Sales Objections",
6371
+ url: "https://www.gong.io/blog/sales-objections",
6372
+ snippet: "Gong sales research and revenue guidance on common sales objections, buyer conditions, objection categories, conversation handling, and evidence-backed sales response patterns.",
6373
+ score: 0.84
6374
+ },
6375
+ {
6376
+ title: "OpenView: Product-Led Sales and SaaS Revenue Guidance",
6377
+ url: "https://openviewpartners.com/blog/",
6378
+ snippet: "OpenView SaaS operating guidance covering product-led growth, sales motions, customer acquisition, pricing, buyer friction, and go-to-market execution for B2B software companies.",
6379
+ score: 0.8
6380
+ },
6381
+ {
6382
+ title: "SaaStr: SaaS Sales and Revenue Playbooks",
6383
+ url: "https://www.saastr.com/category/sales/",
6384
+ snippet: "SaaStr sales playbooks and SaaS revenue guidance covering enterprise sales, objections, buyer process, procurement friction, pricing concerns, customer success, and go-to-market execution.",
6385
+ score: 0.78
6386
+ },
6387
+ {
6388
+ title: "Pipedrive: Overcoming Sales Objections",
6389
+ url: "https://www.pipedrive.com/en/blog/overcoming-sales-objections",
6390
+ snippet: "Pipedrive sales guidance on reframing buyer concerns, planning objection handling with a team, trust objections, value positioning, and tracking lost-deal reasons in a sales workflow.",
6391
+ score: 0.78
6392
+ },
6393
+ {
6394
+ title: "Zendesk: How to Overcome Common Sales Objections",
6395
+ url: "https://www.zendesk.com/blog/sales/proven-sales-techniques/overcome-common-sales-objections/",
6396
+ snippet: "Zendesk Sell guidance defining sales objections and covering practical techniques for responding to buyer concerns, lead resistance, and preventable deal loss.",
6397
+ score: 0.77
6398
+ },
6399
+ {
6400
+ title: "Salesloft: Objection Handling for Sales Teams",
6401
+ url: "https://www.salesloft.com/resources/blog/4-steps-to-help-your-sales-team-nail-objection-handling",
6402
+ snippet: "Salesloft revenue-team guidance on operationalizing objection handling, surfacing buyer objections early, coaching sales teams, and improving sales-process discipline.",
6403
+ score: 0.76
6404
+ },
6405
+ {
6406
+ title: "Close: Sales Objection Handling Resources",
6407
+ url: "https://www.close.com/blog/sales-objection-handling",
6408
+ snippet: "Close sales guidance for objection handling, sales scripts, buyer resistance, pricing concerns, timing objections, and practical response patterns for sales teams.",
6409
+ score: 0.74
6410
+ }
6411
+ ]
6412
+ },
6133
6413
  {
6134
6414
  id: "developer-docs",
6135
6415
  label: "Developer Documentation",
@@ -6197,9 +6477,16 @@ var TOPIC_STOP_WORDS = /* @__PURE__ */ new Set([
6197
6477
  "examples",
6198
6478
  "example",
6199
6479
  "with",
6480
+ "and",
6481
+ "the",
6482
+ "for",
6483
+ "how",
6200
6484
  "from",
6201
6485
  "into",
6202
6486
  "about",
6487
+ "benefit",
6488
+ "benefits",
6489
+ "beneficial",
6203
6490
  "info",
6204
6491
  "information",
6205
6492
  "generate",
@@ -6228,6 +6515,21 @@ var CODE_TOPIC_TERMS = [
6228
6515
  "python",
6229
6516
  "javascript"
6230
6517
  ];
6518
+ var DATASET_ARTIFACT_TERMS = [
6519
+ "dataset",
6520
+ "datasets",
6521
+ "corpus",
6522
+ "csv",
6523
+ "jsonl",
6524
+ "parquet",
6525
+ "kaggle",
6526
+ "huggingface",
6527
+ "benchmark",
6528
+ "tabular",
6529
+ "table",
6530
+ "open data",
6531
+ "public data"
6532
+ ];
6231
6533
  var BROAD_SOURCE_TERMS = [
6232
6534
  "awesome",
6233
6535
  "tutorial",
@@ -7331,7 +7633,7 @@ async function generateWithOpenAI(options) {
7331
7633
  };
7332
7634
  }
7333
7635
  async function generateWithOpenAIBatched(options) {
7334
- const batchSize = Math.max(1, Math.min(48, Number(process.env.ALYS_OPENAI_RECORDS_PER_CALL ?? 8)));
7636
+ const batchSize = Math.max(1, Math.min(64, Number(process.env.ALYS_OPENAI_RECORDS_PER_CALL ?? 8)));
7335
7637
  const batches = Array.from(
7336
7638
  { length: Math.ceil(options.targetCount / batchSize) },
7337
7639
  (_, index) => Math.min(batchSize, Math.max(0, options.targetCount - index * batchSize))
@@ -7731,6 +8033,7 @@ var StructuringAgent = class {
7731
8033
  const mapped = providerResult.records.map((g, variantIndex) => {
7732
8034
  const adjustedConfidence = trustWeightedConfidence(g.confidence, baselineConfidence, document, finding, sourceWeight, provenance.corroborationScore);
7733
8035
  const confidenceFactors = confidenceFactorsForRecord(document, finding, provenance, adjustedConfidence, sourceWeight);
8036
+ const acceptance = acceptanceReasons(document, finding, segment2, provenance);
7734
8037
  return {
7735
8038
  id: `${baseId}-${variantIndex}`,
7736
8039
  input: g.input,
@@ -7763,6 +8066,7 @@ var StructuringAgent = class {
7763
8066
  contradiction_notes: finding?.contradictions ?? [],
7764
8067
  contradiction_status: (finding?.contradictions.length ?? 0) > 0 ? "needs_review" : "clear",
7765
8068
  confidence_factors: confidenceFactors,
8069
+ source_fingerprint_version: "2026-05-15",
7766
8070
  source_quality_weight: Number(sourceWeight.toFixed(3)),
7767
8071
  source_trust_score: document.sourceScores?.trustScore,
7768
8072
  source_authority_score: document.sourceScores?.authorityScore,
@@ -7770,8 +8074,9 @@ var StructuringAgent = class {
7770
8074
  source_domain_alignment_score: document.sourceScores?.domainAlignmentScore,
7771
8075
  source_freshness_score: document.sourceScores?.freshnessScore,
7772
8076
  source_duplication_risk: document.sourceScores?.duplicationRisk,
7773
- acceptance_reasons: acceptanceReasons(document, finding, segment2, provenance)
8077
+ acceptance_reasons: acceptance
7774
8078
  },
8079
+ sourceFingerprint: buildSourceFingerprint(document, finding, provenance, confidenceFactors, acceptance),
7775
8080
  created_at: createdAt
7776
8081
  };
7777
8082
  });
@@ -7891,6 +8196,47 @@ function buildRecordProvenance(document, finding, documents = []) {
7891
8196
  corroborationScore: Number(corroborationScore.toFixed(3))
7892
8197
  };
7893
8198
  }
8199
+ function buildSourceFingerprint(document, finding, provenance, confidenceFactors, acceptanceReasons2) {
8200
+ const contradictions = finding?.contradictions ?? [];
8201
+ const weakSignals = [
8202
+ ...provenance.supportUrls.length < 2 ? ["thin-source-support"] : [],
8203
+ ...(document.sourceScores?.domainAlignmentScore ?? document.sourceScores?.relevanceScore ?? 0) < 0.5 ? ["low-topic-alignment"] : [],
8204
+ ...(document.sourceScores?.freshnessScore ?? 1) < 0.45 ? ["low-freshness"] : [],
8205
+ ...(document.sourceScores?.duplicationRisk ?? 0) > 0.35 ? ["high-duplication-risk"] : [],
8206
+ ...contradictions.length ? ["open-contradictions"] : []
8207
+ ];
8208
+ return {
8209
+ primary: {
8210
+ sourceId: document.sourceId,
8211
+ title: document.title,
8212
+ url: document.url,
8213
+ domain: provenance.primaryDomain,
8214
+ trustScore: document.sourceScores?.trustScore,
8215
+ authorityScore: document.sourceScores?.authorityScore,
8216
+ relevanceScore: document.sourceScores?.relevanceScore,
8217
+ freshnessScore: document.sourceScores?.freshnessScore,
8218
+ alignmentScore: document.sourceScores?.domainAlignmentScore,
8219
+ duplicationRisk: document.sourceScores?.duplicationRisk
8220
+ },
8221
+ support: provenance.supportSources.map((source) => ({
8222
+ ...source,
8223
+ relation: source.url === document.url ? "primary" : "supporting"
8224
+ })),
8225
+ confidenceFactors,
8226
+ contradictions: {
8227
+ status: contradictions.length ? "needs_review" : "clear",
8228
+ count: contradictions.length,
8229
+ notes: contradictions
8230
+ },
8231
+ provenance: {
8232
+ supportCount: provenance.supportUrls.length,
8233
+ supportDomains: provenance.supportDomains,
8234
+ corroborationScore: provenance.corroborationScore,
8235
+ acceptanceReasons: acceptanceReasons2,
8236
+ weakSignals
8237
+ }
8238
+ };
8239
+ }
7894
8240
  function confidenceFactorsForRecord(document, finding, provenance, confidence, sourceWeight) {
7895
8241
  const authority = document.sourceScores?.authorityScore ?? 0.55;
7896
8242
  const trust = document.sourceScores?.trustScore ?? 0.62;
@@ -7950,6 +8296,7 @@ function toCsv(records) {
7950
8296
  "source_trust_score",
7951
8297
  "source_authority_score",
7952
8298
  "source_relevance_score",
8299
+ "source_fingerprint",
7953
8300
  "tags",
7954
8301
  "metadata",
7955
8302
  "created_at"
@@ -7967,6 +8314,7 @@ function toCsv(records) {
7967
8314
  metadataString(record, "source_trust_score"),
7968
8315
  metadataString(record, "source_authority_score"),
7969
8316
  metadataString(record, "source_relevance_score"),
8317
+ record.sourceFingerprint ? JSON.stringify(record.sourceFingerprint) : "",
7970
8318
  record.tags.join("|"),
7971
8319
  JSON.stringify(record.metadata),
7972
8320
  record.created_at
@@ -7987,12 +8335,19 @@ function toMarkdown(records) {
7987
8335
 
7988
8336
  Context:
7989
8337
  ${record.context}` : ""].join("");
8338
+ const fingerprint = record.sourceFingerprint ? `
8339
+ Source fingerprint:
8340
+ - Primary: ${record.sourceFingerprint.primary.title} (${record.sourceFingerprint.primary.domain})
8341
+ - Support: ${record.sourceFingerprint.provenance.supportCount} source(s)
8342
+ - Corroboration: ${record.sourceFingerprint.provenance.corroborationScore}
8343
+ - Weak signals: ${record.sourceFingerprint.provenance.weakSignals.join(", ") || "none"}
8344
+ ` : "";
7990
8345
  return `## ${title}
7991
8346
 
7992
8347
  ${body}
7993
8348
 
7994
8349
  Confidence: ${record.confidence}
7995
- Source: ${record.source} (${record.source_url})
8350
+ Source: ${record.source} (${record.source_url})${fingerprint}
7996
8351
  Tags: ${record.tags.join(", ")}
7997
8352
  Created: ${record.created_at}
7998
8353
  `;
@@ -8017,6 +8372,7 @@ function serializeDataset(records, format) {
8017
8372
  context: r.context,
8018
8373
  source_url: r.source_url,
8019
8374
  confidence: r.confidence,
8375
+ source_fingerprint: r.sourceFingerprint,
8020
8376
  tags: r.tags,
8021
8377
  metadata: r.metadata,
8022
8378
  created_at: r.created_at
@@ -8031,6 +8387,7 @@ function serializeDataset(records, format) {
8031
8387
  text: r.context,
8032
8388
  source_url: r.source_url,
8033
8389
  confidence: r.confidence,
8390
+ source_fingerprint: r.sourceFingerprint,
8034
8391
  tags: r.tags,
8035
8392
  metadata: r.metadata,
8036
8393
  created_at: r.created_at
@@ -10287,8 +10644,8 @@ var CONFIG_DIR = import_node_path5.default.join(import_node_os4.default.homedir(
10287
10644
  var CONFIG_PATH = import_node_path5.default.join(CONFIG_DIR, "config.json");
10288
10645
  var ALYS_APP_URL = process.env.ALYS_APP_URL || process.env.NEXT_PUBLIC_SITE_URL || "https://alys.akusa.dev";
10289
10646
  var MAX_DATASETS_PER_RUN = 5;
10290
- var MAX_SOURCES_PER_RUN = 8;
10291
- var MAX_ROWS_PER_DATASET = 125;
10647
+ var MAX_SOURCES_PER_RUN = 16;
10648
+ var MAX_ROWS_PER_DATASET = 500;
10292
10649
  var MAX_BENCHMARK_SOURCES_PER_RUN = 96;
10293
10650
  var MAX_BENCHMARK_ROWS_PER_DATASET = 25e3;
10294
10651
  var FIGLET_LOGO = [
@@ -10333,8 +10690,8 @@ Flags:
10333
10690
  --datasets 1
10334
10691
  --depth shallow|medium|deep
10335
10692
  --mode fast|balanced|strict|maximum-quality
10336
- --sources 8
10337
- --rows 125
10693
+ --sources 16
10694
+ --rows 500
10338
10695
  --workspace ~/Desktop/alys-output
10339
10696
  --verify
10340
10697
  --no-verify
@@ -10648,6 +11005,37 @@ async function withSpinner(label, task) {
10648
11005
  throw error;
10649
11006
  }
10650
11007
  }
11008
+ async function withRuntimeProgress(args, task) {
11009
+ const stages = [
11010
+ ["SRC", "Searching and diversifying trusted sources", `${args.sourceLimit} target`],
11011
+ ["RANK", "Scoring authority, freshness, and topic alignment", args.depth],
11012
+ ["EXT", "Normalizing source evidence for grounded generation", "hosted"],
11013
+ ["GEN", "Generating source-grounded record batches", `${formatInt2(args.datasetCount * args.targetRows)} target rows`],
11014
+ ["CHK", "Filtering unsupported and repetitive records", args.performanceMode],
11015
+ ["EVAL", "Scoring confidence, citations, and usefulness", "quality gate"],
11016
+ ["OUT", "Packaging exports for local write", "jsonl/csv/rag"]
11017
+ ];
11018
+ let stageIndex = 0;
11019
+ let elapsedSeconds = 0;
11020
+ printStage(stages[0][0], "RUN", stages[0][1], stages[0][2]);
11021
+ const interval = setInterval(() => {
11022
+ elapsedSeconds += 6;
11023
+ stageIndex = Math.min(stageIndex + 1, stages.length - 1);
11024
+ const [code, label, metric] = stages[stageIndex];
11025
+ const suffix = elapsedSeconds >= 48 ? `${metric} \xB7 ${elapsedSeconds}s \xB7 larger runs can take a few minutes` : metric;
11026
+ printStage(code, "RUN", label, suffix);
11027
+ }, 6e3);
11028
+ try {
11029
+ const result = await task;
11030
+ clearInterval(interval);
11031
+ printStage("RUN", "DONE", "Alys runtime completed", "server response received");
11032
+ return result;
11033
+ } catch (error) {
11034
+ clearInterval(interval);
11035
+ printStage("RUN", "WARN", "Alys runtime stopped before completion", "no generations spent on failure");
11036
+ throw error;
11037
+ }
11038
+ }
10651
11039
  function previewRecord(dataset) {
10652
11040
  const file = dataset.files.find((item) => item.format === "jsonl" || item.format === "instruction" || item.format === "rag");
10653
11041
  const firstLine = file?.content.split(/\r?\n/).find((line) => line.trim().length > 0);
@@ -11494,8 +11882,14 @@ async function handleGenerate(args, command) {
11494
11882
  printStage("AUTH", "OK", "Usage linked", appUrl());
11495
11883
  printStage("PLAN", "OK", "Generations charged only after successful completion", `${datasetCount} requested`);
11496
11884
  printStage("RUN", "RUN", "Dataset runtime starting", `${performanceMode} mode`);
11497
- const response = await withSpinner(
11498
- "Alys runtime executing",
11885
+ const response = await withRuntimeProgress(
11886
+ {
11887
+ datasetCount,
11888
+ sourceLimit,
11889
+ targetRows,
11890
+ depth,
11891
+ performanceMode
11892
+ },
11499
11893
  requestJson(
11500
11894
  "/api/cli/generate",
11501
11895
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "alys-akusa",
3
- "version": "0.1.20",
3
+ "version": "0.1.22",
4
4
  "private": false,
5
5
  "description": "Alys local CLI runtime for autonomous AI data preparation.",
6
6
  "license": "UNLICENSED",