atris 3.15.0 → 3.15.12

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/wiki.js CHANGED
@@ -457,7 +457,20 @@ function readWikiPages(projectRoot = process.cwd(), mode = 'public') {
457
457
 
458
458
  function normalizeSourcePath(projectRoot, source) {
459
459
  if (!source || /^https?:\/\//i.test(source)) return null;
460
+ // Source receipts may be external system labels such as "hubspot",
461
+ // "chorus", or "greenhouse". They are valid evidence labels but not local
462
+ // files, so stale-file checks should not mark them missing.
463
+ if (!/[/.]/.test(source)) return null;
460
464
  if (path.isAbsolute(source)) return path.normalize(source);
465
+ if (source.startsWith('context/')) {
466
+ const atrisContextPath = path.normalize(path.join(projectRoot, 'atris', source));
467
+ if (fs.existsSync(atrisContextPath)) return atrisContextPath;
468
+ }
469
+ if (source.startsWith('team/')) {
470
+ const atrisTeamPath = path.normalize(path.join(projectRoot, 'atris', source));
471
+ if (fs.existsSync(atrisTeamPath)) return atrisTeamPath;
472
+ }
473
+ if (/^(chorus|hubspot|greenhouse)\//.test(source)) return null;
461
474
  return path.normalize(path.join(projectRoot, source));
462
475
  }
463
476
 
@@ -503,9 +516,20 @@ function findStaleWikiPages(projectRoot = process.cwd(), mode = 'public') {
503
516
  .filter(Boolean);
504
517
  }
505
518
 
506
- function extractWikiLinks(content) {
519
+ function extractWikiLinks(content, wikiRoot = WIKI_ROOT) {
507
520
  const matches = content.match(/\[\[((?:atris\/wiki|\.atris\/presidio)\/[^\]]+?)\]\]/g) || [];
508
- return matches.map((match) => match.slice(2, -2));
521
+ const links = matches.map((match) => match.slice(2, -2));
522
+ const markdownMatches = content.matchAll(/\[[^\]]+\]\(([^)]+\.md)\)/g);
523
+ for (const match of markdownMatches) {
524
+ const raw = String(match[1] || '').trim();
525
+ if (!raw || /^https?:\/\//i.test(raw) || raw.startsWith('#')) continue;
526
+ if (raw.startsWith(`${wikiRoot}/`)) {
527
+ links.push(raw);
528
+ } else if (!raw.startsWith('/') && !raw.startsWith('..')) {
529
+ links.push(`${wikiRoot}/${raw}`.replace(/\/+/g, '/'));
530
+ }
531
+ }
532
+ return links;
509
533
  }
510
534
 
511
535
  function findWikiOrphans(projectRoot = process.cwd(), mode = 'public') {
@@ -519,8 +543,10 @@ function findWikiOrphans(projectRoot = process.cwd(), mode = 'public') {
519
543
  inboundLinks.set(page.relativePath, 0);
520
544
  }
521
545
 
546
+ const indexLinks = new Set(extractWikiLinks(indexContent, wikiRoot).map((link) => link.replace(/\\/g, '/')));
547
+
522
548
  for (const page of pages) {
523
- const links = extractWikiLinks(page.content);
549
+ const links = extractWikiLinks(page.content, wikiRoot);
524
550
  for (const link of links) {
525
551
  const normalized = link.replace(/\\/g, '/');
526
552
  if (normalized !== page.relativePath && inboundLinks.has(normalized)) {
@@ -531,13 +557,66 @@ function findWikiOrphans(projectRoot = process.cwd(), mode = 'public') {
531
557
 
532
558
  return pages
533
559
  .filter((page) => {
534
- const indexed = indexContent.includes(`[[${page.relativePath}]]`);
560
+ const indexed = indexContent.includes(`[[${page.relativePath}]]`) || indexLinks.has(page.relativePath);
535
561
  const inboundCount = inboundLinks.get(page.relativePath) || 0;
536
562
  return !indexed && inboundCount === 0;
537
563
  })
538
564
  .map((page) => page.relativePath);
539
565
  }
540
566
 
567
+ function hasFrontmatterKey(frontmatter, key) {
568
+ return Object.prototype.hasOwnProperty.call(frontmatter || {}, key);
569
+ }
570
+
571
+ function isIsoDate(value) {
572
+ return typeof value === 'string' && /^\d{4}-\d{2}-\d{2}$/.test(value);
573
+ }
574
+
575
+ function isConfidence(value) {
576
+ const n = Number(value);
577
+ return Number.isFinite(n) && n >= 0 && n <= 1;
578
+ }
579
+
580
+ function validateAgentReadableWikiPages(projectRoot = process.cwd(), mode = 'public') {
581
+ const findings = [];
582
+ const pages = readWikiPages(projectRoot, mode);
583
+ const stalePages = new Set(findStaleWikiPages(projectRoot, mode).map((item) => item.page));
584
+
585
+ for (const page of pages) {
586
+ const fm = page.frontmatter || {};
587
+ const sources = Array.isArray(fm.sources) ? fm.sources.filter(Boolean) : [];
588
+
589
+ if (sources.length === 0) {
590
+ findings.push({ page: page.relativePath, code: 'missing-sources', message: 'missing source receipt in frontmatter sources' });
591
+ }
592
+ if (!isIsoDate(fm.last_compiled)) {
593
+ findings.push({ page: page.relativePath, code: 'missing-last-compiled', message: 'missing YYYY-MM-DD last_compiled' });
594
+ }
595
+ if (!isIsoDate(fm.last_verified)) {
596
+ findings.push({ page: page.relativePath, code: 'missing-last-verified', message: 'missing YYYY-MM-DD last_verified' });
597
+ }
598
+ if (!isConfidence(fm.confidence)) {
599
+ findings.push({ page: page.relativePath, code: 'missing-confidence', message: 'confidence must be a number from 0 to 1' });
600
+ }
601
+ if (!hasFrontmatterKey(fm, 'dependencies') || !Array.isArray(fm.dependencies)) {
602
+ findings.push({ page: page.relativePath, code: 'missing-dependencies', message: 'dependencies must be present as a list, even if empty' });
603
+ }
604
+ if (!String(fm.actionability || '').trim()) {
605
+ findings.push({ page: page.relativePath, code: 'missing-actionability', message: 'missing actionability summary' });
606
+ }
607
+ if (stalePages.has(page.relativePath)) {
608
+ findings.push({ page: page.relativePath, code: 'stale-source', message: 'source changed since last_compiled or source is missing' });
609
+ }
610
+ }
611
+
612
+ return {
613
+ ok: findings.length === 0,
614
+ pageCount: pages.length,
615
+ findingCount: findings.length,
616
+ findings,
617
+ };
618
+ }
619
+
541
620
  function findSuggestedSources(projectRoot = process.cwd(), limit = 3) {
542
621
  const candidates = [
543
622
  'README.md',
@@ -743,6 +822,7 @@ module.exports = {
743
822
  readWikiPages,
744
823
  findStaleWikiPages,
745
824
  findWikiOrphans,
825
+ validateAgentReadableWikiPages,
746
826
  findSuggestedSources,
747
827
  stageWikiIngest,
748
828
  writeWikiStatus,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "atris",
3
- "version": "3.15.0",
3
+ "version": "3.15.12",
4
4
  "description": "Atris — an operating system for intelligence. Integrates with any agent.",
5
5
  "main": "bin/atris.js",
6
6
  "bin": {
@@ -29,6 +29,7 @@
29
29
  "atris/team/researcher/MEMBER.md",
30
30
  "atris/team/_template/MEMBER.md",
31
31
  "atris/features/_templates/",
32
+ "atris/features/company-brain-sync/",
32
33
  "atris/policies/",
33
34
  "atris/skills/"
34
35
  ],
@@ -56,5 +57,14 @@
56
57
  "repository": {
57
58
  "type": "git",
58
59
  "url": "git+https://github.com/atrislabs/atris.git"
59
- }
60
+ },
61
+ "directories": {
62
+ "lib": "lib",
63
+ "test": "test"
64
+ },
65
+ "type": "commonjs",
66
+ "bugs": {
67
+ "url": "https://github.com/atrislabs/atris/issues"
68
+ },
69
+ "homepage": "https://github.com/atrislabs/atris#readme"
60
70
  }