wayfind 2.0.32 → 2.0.34
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/bin/content-store.js +31 -1
- package/bin/storage/index.js +18 -1
- package/bin/team-context.js +16 -3
- package/doctor.sh +103 -4
- package/package.json +1 -1
package/bin/content-store.js
CHANGED
|
@@ -569,8 +569,38 @@ function searchText(query, options = {}) {
|
|
|
569
569
|
...(entry.tags || []),
|
|
570
570
|
].filter(Boolean).join(' ').toLowerCase().replace(/[-_]/g, ' ');
|
|
571
571
|
|
|
572
|
+
// For signal entries, read content directly from the signal file
|
|
573
|
+
if (entry.source === 'signal') {
|
|
574
|
+
const signalsDir = options.signalsDir || DEFAULT_SIGNALS_DIR;
|
|
575
|
+
if (signalsDir) {
|
|
576
|
+
// Signal files live at signalsDir/<channel>/<date>.md or signalsDir/<channel>/<owner>/<repo>/<date>.md
|
|
577
|
+
// The repo field tells us the path: "signals/<channel>" or "<owner>/<repo>"
|
|
578
|
+
const repo = entry.repo || '';
|
|
579
|
+
const candidates = [];
|
|
580
|
+
if (repo.startsWith('signals/')) {
|
|
581
|
+
const channel = repo.replace('signals/', '');
|
|
582
|
+
candidates.push(path.join(signalsDir, channel, `${entry.date}.md`));
|
|
583
|
+
candidates.push(path.join(signalsDir, channel, `${entry.date}-summary.md`));
|
|
584
|
+
} else if (repo.includes('/')) {
|
|
585
|
+
// owner/repo format — find which channel it's under
|
|
586
|
+
for (const channel of ['github', 'intercom', 'notion']) {
|
|
587
|
+
candidates.push(path.join(signalsDir, channel, repo, `${entry.date}.md`));
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
for (const fp of candidates) {
|
|
591
|
+
try {
|
|
592
|
+
const content = fs.readFileSync(fp, 'utf8').toLowerCase();
|
|
593
|
+
searchable += ' ' + content.replace(/[-_]/g, ' ');
|
|
594
|
+
break;
|
|
595
|
+
} catch {
|
|
596
|
+
// Try next candidate
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
|
|
572
602
|
// Also include the full journal entry content if available
|
|
573
|
-
const journalContent = getJournalContent(entry.date, entry.user);
|
|
603
|
+
const journalContent = entry.source !== 'signal' ? getJournalContent(entry.date, entry.user) : null;
|
|
574
604
|
if (journalContent) {
|
|
575
605
|
// Find this entry's section in the journal file.
|
|
576
606
|
// Try exact match first, then normalize hyphens/spaces for fuzzy match.
|
package/bin/storage/index.js
CHANGED
|
@@ -126,7 +126,9 @@ function getBackend(storePath) {
|
|
|
126
126
|
migrateFromJson(backend, storePath);
|
|
127
127
|
cache[storePath] = backend;
|
|
128
128
|
return backend;
|
|
129
|
-
} catch {
|
|
129
|
+
} catch (err) {
|
|
130
|
+
console.error('Warning: SQLite backend failed to initialize, falling back to JSON.', err.message);
|
|
131
|
+
cache[storePath + ':fallback'] = true;
|
|
130
132
|
const backend = new JsonBackend(storePath);
|
|
131
133
|
backend.open();
|
|
132
134
|
cache[storePath] = backend;
|
|
@@ -164,8 +166,23 @@ function getBackendType(storePath) {
|
|
|
164
166
|
return null;
|
|
165
167
|
}
|
|
166
168
|
|
|
169
|
+
/**
|
|
170
|
+
* Returns detailed backend info including whether it was a silent fallback.
|
|
171
|
+
*
|
|
172
|
+
* @param {string} storePath
|
|
173
|
+
* @returns {{ type: 'sqlite'|'json'|'unknown', storePath: string, fallback: boolean }|null}
|
|
174
|
+
*/
|
|
175
|
+
function getBackendInfo(storePath) {
|
|
176
|
+
const backend = cache[storePath];
|
|
177
|
+
if (!backend) return null;
|
|
178
|
+
const type = backend instanceof JsonBackend ? 'json' :
|
|
179
|
+
(backend.constructor && backend.constructor.name === 'SqliteBackend') ? 'sqlite' : 'unknown';
|
|
180
|
+
return { type, storePath, fallback: !!cache[storePath + ':fallback'] };
|
|
181
|
+
}
|
|
182
|
+
|
|
167
183
|
module.exports = {
|
|
168
184
|
getBackend,
|
|
169
185
|
clearCache,
|
|
170
186
|
getBackendType,
|
|
187
|
+
getBackendInfo,
|
|
171
188
|
};
|
package/bin/team-context.js
CHANGED
|
@@ -4370,10 +4370,10 @@ function ensureContainerConfig() {
|
|
|
4370
4370
|
}
|
|
4371
4371
|
}
|
|
4372
4372
|
|
|
4373
|
-
// GitHub connector
|
|
4374
|
-
if (
|
|
4373
|
+
// GitHub connector — create if missing, or fix transport if mounted config has gh-cli
|
|
4374
|
+
if (process.env.GITHUB_TOKEN) {
|
|
4375
4375
|
const repos = process.env.TEAM_CONTEXT_GITHUB_REPOS;
|
|
4376
|
-
if (repos) {
|
|
4376
|
+
if (!config.github && repos) {
|
|
4377
4377
|
config.github = {
|
|
4378
4378
|
transport: 'https',
|
|
4379
4379
|
token: process.env.GITHUB_TOKEN,
|
|
@@ -4382,6 +4382,19 @@ function ensureContainerConfig() {
|
|
|
4382
4382
|
last_pull: null,
|
|
4383
4383
|
};
|
|
4384
4384
|
changed = true;
|
|
4385
|
+
} else if (config.github) {
|
|
4386
|
+
// Override gh-cli transport in container context — gh binary isn't available
|
|
4387
|
+
if (config.github.transport === 'gh-cli') {
|
|
4388
|
+
config.github.transport = 'https';
|
|
4389
|
+
config.github.token = process.env.GITHUB_TOKEN;
|
|
4390
|
+
config.github.token_env = 'GITHUB_TOKEN';
|
|
4391
|
+
changed = true;
|
|
4392
|
+
}
|
|
4393
|
+
// Backfill repos from env if config has none or env specifies them
|
|
4394
|
+
if (repos && (!config.github.repos || config.github.repos.length === 0)) {
|
|
4395
|
+
config.github.repos = repos.split(',').map((r) => r.trim());
|
|
4396
|
+
changed = true;
|
|
4397
|
+
}
|
|
4385
4398
|
}
|
|
4386
4399
|
}
|
|
4387
4400
|
|
package/doctor.sh
CHANGED
|
@@ -357,17 +357,116 @@ check_storage_backend() {
|
|
|
357
357
|
echo ""
|
|
358
358
|
echo "Storage backend"
|
|
359
359
|
|
|
360
|
+
set +e # Temporarily disable errexit — node calls may fail in test environments
|
|
360
361
|
# Check for env var override
|
|
361
362
|
if [ -n "${TEAM_CONTEXT_STORAGE_BACKEND:-}" ]; then
|
|
362
363
|
info "TEAM_CONTEXT_STORAGE_BACKEND=$TEAM_CONTEXT_STORAGE_BACKEND (env override)"
|
|
363
364
|
fi
|
|
364
365
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
366
|
+
local WAYFIND_DIR="${WAYFIND_DIR:-$HOME/.claude/team-context}"
|
|
367
|
+
local SCRIPT_DIR
|
|
368
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
369
|
+
|
|
370
|
+
# ── 1. Which backend is active ───────────────────────────────────────────
|
|
371
|
+
local BACKEND_RESULT=""
|
|
372
|
+
BACKEND_RESULT=$(node -e "
|
|
373
|
+
try {
|
|
374
|
+
const storage = require('$SCRIPT_DIR/bin/storage/index.js');
|
|
375
|
+
const storePath = '$WAYFIND_DIR';
|
|
376
|
+
storage.getBackend(storePath);
|
|
377
|
+
const info = storage.getBackendInfo(storePath);
|
|
378
|
+
if (!info) { console.log('NONE'); process.exit(0); }
|
|
379
|
+
console.log(JSON.stringify(info));
|
|
380
|
+
} catch (e) {
|
|
381
|
+
console.log('SKIP:' + e.message.split('\n')[0]);
|
|
382
|
+
}
|
|
383
|
+
" 2>/dev/null) || BACKEND_RESULT="SKIP:storage module not available"
|
|
384
|
+
|
|
385
|
+
if [[ "$BACKEND_RESULT" == SKIP:* ]]; then
|
|
386
|
+
[ "$VERBOSE" = true ] && info "Storage check skipped: ${BACKEND_RESULT#SKIP:}"
|
|
387
|
+
elif [[ "$BACKEND_RESULT" == "NONE" ]]; then
|
|
388
|
+
info "No storage backend initialized (team-context not configured)"
|
|
389
|
+
else
|
|
390
|
+
local BACKEND_TYPE
|
|
391
|
+
BACKEND_TYPE=$(echo "$BACKEND_RESULT" | node -e "const d=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')); console.log(d.type)" 2>/dev/null || echo "unknown")
|
|
392
|
+
local IS_FALLBACK
|
|
393
|
+
IS_FALLBACK=$(echo "$BACKEND_RESULT" | node -e "const d=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')); console.log(d.fallback)" 2>/dev/null || echo "false")
|
|
394
|
+
|
|
395
|
+
if [ "$BACKEND_TYPE" = "sqlite" ]; then
|
|
396
|
+
ok "Active backend: sqlite"
|
|
397
|
+
elif [ "$BACKEND_TYPE" = "json" ]; then
|
|
398
|
+
ok "Active backend: json"
|
|
399
|
+
else
|
|
400
|
+
warn "Active backend: $BACKEND_TYPE (unexpected)"
|
|
401
|
+
fi
|
|
402
|
+
|
|
403
|
+
# ── 2. Fallback detection ────────────────────────────────────────────
|
|
404
|
+
if [ "$IS_FALLBACK" = "true" ]; then
|
|
405
|
+
warn "JSON backend is a fallback — better-sqlite3 was expected but failed to load"
|
|
406
|
+
info "Run: npm install -g better-sqlite3 (or reinstall wayfind)"
|
|
407
|
+
ISSUES=$((ISSUES + 1))
|
|
408
|
+
elif [ "$BACKEND_TYPE" = "json" ]; then
|
|
409
|
+
# Not a runtime fallback — check if sqlite3 is available but unused
|
|
410
|
+
if node -e "require('better-sqlite3')" 2>/dev/null; then
|
|
411
|
+
warn "better-sqlite3 is installed but backend is JSON — possible unexpected fallback"
|
|
412
|
+
info "Check TEAM_CONTEXT_STORAGE_BACKEND env var or re-run setup"
|
|
413
|
+
ISSUES=$((ISSUES + 1))
|
|
414
|
+
else
|
|
415
|
+
[ "$VERBOSE" = true ] && info "better-sqlite3 not installed — JSON is expected"
|
|
416
|
+
fi
|
|
417
|
+
fi
|
|
418
|
+
fi
|
|
419
|
+
|
|
420
|
+
# ── 3. Signal freshness (connectors.json last_pull) ──────────────────────
|
|
421
|
+
local CONNECTORS="$WAYFIND_DIR/connectors.json"
|
|
422
|
+
if [ -f "$CONNECTORS" ]; then
|
|
423
|
+
local FRESHNESS_RESULT
|
|
424
|
+
FRESHNESS_RESULT=$(node -e "
|
|
425
|
+
const fs = require('fs');
|
|
426
|
+
const config = JSON.parse(fs.readFileSync('$CONNECTORS', 'utf8'));
|
|
427
|
+
const connectors = ['github', 'intercom', 'notion'];
|
|
428
|
+
const now = Date.now();
|
|
429
|
+
const DAY = 24 * 60 * 60 * 1000;
|
|
430
|
+
const results = [];
|
|
431
|
+
for (const name of connectors) {
|
|
432
|
+
const c = config[name];
|
|
433
|
+
if (!c) continue;
|
|
434
|
+
const lp = c.last_pull;
|
|
435
|
+
if (!lp) {
|
|
436
|
+
results.push('WARN:' + name + ':never pulled');
|
|
437
|
+
} else {
|
|
438
|
+
const age = now - new Date(lp).getTime();
|
|
439
|
+
const hours = Math.floor(age / (60 * 60 * 1000));
|
|
440
|
+
if (age > DAY) {
|
|
441
|
+
results.push('WARN:' + name + ':' + hours + 'h ago');
|
|
442
|
+
} else {
|
|
443
|
+
results.push('OK:' + name + ':' + hours + 'h ago');
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
console.log(results.join('|'));
|
|
448
|
+
" 2>/dev/null) || FRESHNESS_RESULT=""
|
|
449
|
+
|
|
450
|
+
if [ -n "$FRESHNESS_RESULT" ]; then
|
|
451
|
+
IFS='|' read -ra ENTRIES <<< "$FRESHNESS_RESULT"
|
|
452
|
+
for entry in "${ENTRIES[@]}"; do
|
|
453
|
+
local STATUS="${entry%%:*}"
|
|
454
|
+
local REST="${entry#*:}"
|
|
455
|
+
local NAME="${REST%%:*}"
|
|
456
|
+
local DETAIL="${REST#*:}"
|
|
457
|
+
if [ "$STATUS" = "WARN" ]; then
|
|
458
|
+
warn "Signal $NAME: $DETAIL"
|
|
459
|
+
info "Run: wayfind pull $NAME"
|
|
460
|
+
ISSUES=$((ISSUES + 1))
|
|
461
|
+
else
|
|
462
|
+
ok "Signal $NAME: last pull $DETAIL"
|
|
463
|
+
fi
|
|
464
|
+
done
|
|
465
|
+
fi
|
|
368
466
|
else
|
|
369
|
-
|
|
467
|
+
[ "$VERBOSE" = true ] && info "No connectors.json — signal freshness check skipped"
|
|
370
468
|
fi
|
|
469
|
+
set -e # Restore errexit
|
|
371
470
|
}
|
|
372
471
|
|
|
373
472
|
# Run checks
|
package/package.json
CHANGED