wayfind 2.0.46 → 2.0.48

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  #!/bin/bash
2
2
  # Daily memory systems comparison report — posts to Slack via bot token.
3
- # Add to crontab: 43 8 * * * /home/greg/repos/greg/wayfind/bin/memory-report.sh
3
+ # Add to crontab: 43 8 * * * $(which wayfind | xargs dirname)/memory-report.sh
4
4
  #
5
5
  # Runs on host (needs access to ~/.claude/projects for auto-memory).
6
6
  # Pulls SLACK_BOT_TOKEN from the wayfind container if not set locally.
@@ -327,28 +327,134 @@ async function teamCreate() {
327
327
  }
328
328
 
329
329
  async function teamJoin(args) {
330
- const teamId = args[0];
330
+ const input = args[0];
331
+ if (!input) {
332
+ console.error('Error: repo URL or path is required.');
333
+ console.error('Usage: wayfind team join <repo-url-or-path>');
334
+ console.error('Example: wayfind team join https://github.com/acme/team-context');
335
+ process.exit(1);
336
+ }
337
+
338
+ // Determine if input is a URL to clone or a local path
339
+ const isUrl = /^https?:\/\/|^git@|^github\.com\//.test(input);
340
+ let repoPath;
341
+
342
+ if (isUrl) {
343
+ // Parse org/repo from URL for clone destination suggestion
344
+ const urlMatch = input.match(/[:/]([^/]+)\/([^/.]+?)(?:\.git)?$/);
345
+ if (!urlMatch) {
346
+ console.error(`Could not parse org/repo from URL: ${input}`);
347
+ process.exit(1);
348
+ }
349
+ const [, org, repo] = urlMatch;
350
+ const orgDir = path.join(HOME, 'repos', org);
351
+ const suggested = fs.existsSync(orgDir)
352
+ ? path.join(orgDir, repo)
353
+ : path.join(HOME, '.claude', 'team-context', repo);
354
+
355
+ let dest = suggested;
356
+ if (fs.existsSync(suggested)) {
357
+ console.log(`\nRepo already cloned at: ${suggested}`);
358
+ const useExisting = await ask(`Use existing clone? [Y/n]: `);
359
+ if (useExisting.toLowerCase() === 'n') {
360
+ const custom = await ask(`Clone to [${suggested}]: `);
361
+ dest = custom ? path.resolve(custom.replace(/^~/, HOME)) : suggested;
362
+ }
363
+ } else {
364
+ const confirm = await ask(`\nClone to ${suggested}? [Y/n]: `);
365
+ if (confirm.toLowerCase() === 'n') {
366
+ const custom = await ask(`Clone to: `);
367
+ if (!custom) { console.error('Destination required.'); process.exit(1); }
368
+ dest = path.resolve(custom.replace(/^~/, HOME));
369
+ }
370
+ console.log(`Cloning ${input}...`);
371
+ const cloneUrl = /^https?:\/\//.test(input) ? input : `https://${input}`;
372
+ const result = spawnSync('git', ['clone', cloneUrl, dest], { stdio: 'inherit' });
373
+ if (result.status !== 0) {
374
+ console.error('Clone failed.');
375
+ process.exit(1);
376
+ }
377
+ }
378
+ repoPath = dest;
379
+ } else {
380
+ repoPath = path.resolve(input.replace(/^~/, HOME));
381
+ if (!fs.existsSync(repoPath)) {
382
+ console.error(`Directory not found: ${repoPath}`);
383
+ process.exit(1);
384
+ }
385
+ }
386
+
387
+ // Read wayfind.json from the repo
388
+ const sharedConfig = readJSONFile(path.join(repoPath, 'wayfind.json')) || {};
389
+ const teamId = sharedConfig.team_id;
331
390
  if (!teamId) {
332
- console.error('Error: team ID is required.');
333
- console.error('Usage: wayfind team join <team-id>');
391
+ console.error('');
392
+ console.error(`Error: wayfind.json in that repo has no team_id.`);
393
+ console.error('Ask your team admin to run:');
394
+ console.error(` wayfind context add <team-id> ${repoPath}`);
334
395
  process.exit(1);
335
396
  }
397
+ const teamName = sharedConfig.team_name || teamId;
398
+ const containerEndpoint = sharedConfig.container_endpoint || null;
336
399
 
337
- const team = {
338
- teamId,
339
- joined: new Date().toISOString(),
400
+ // Register in local context.json
401
+ const config = readContextConfig();
402
+ if (!config.teams) config.teams = {};
403
+ const existing = config.teams[teamId];
404
+ config.teams[teamId] = {
405
+ path: repoPath,
406
+ name: teamName,
407
+ configured_at: new Date().toISOString(),
408
+ ...(containerEndpoint ? { container_endpoint: containerEndpoint } : {}),
409
+ ...(existing && existing.bound_repos ? { bound_repos: existing.bound_repos } : {}),
340
410
  };
411
+ if (!config.default) config.default = teamId;
412
+ writeContextConfig(config);
341
413
 
342
- writeJSONFile(TEAM_FILE, team);
414
+ // Check API key status
415
+ const keyFile = path.join(repoPath, '.wayfind-api-key');
416
+ const keyReady = fs.existsSync(keyFile) && (() => {
417
+ try { return fs.readFileSync(keyFile, 'utf8').trim().length >= 32; } catch { return false; }
418
+ })();
419
+
420
+ // Print confirmation
421
+ console.log('');
422
+ console.log(`Joined team '${teamName}' (${teamId})`);
423
+ console.log(` Repo: ${repoPath}`);
424
+ if (containerEndpoint) {
425
+ console.log(` Semantic search: available | ${containerEndpoint}`);
426
+ } else {
427
+ console.log(` Semantic search: not configured`);
428
+ console.log(` Ask your team admin: wayfind deploy set-endpoint ${teamId} <url>`);
429
+ }
430
+ if (keyReady) {
431
+ console.log(` Search API key: ready — rotates daily, committed to team repo`);
432
+ } else {
433
+ console.log(` Search API key: pending — will appear after the container's first key rotation`);
434
+ console.log(` Run \`git pull\` in ${repoPath} after the container starts`);
435
+ }
436
+ console.log('');
437
+ console.log('How the search key works:');
438
+ console.log(' The container rotates this key every 24 hours and commits it to the team repo.');
439
+ console.log(' Your Claude Code sessions read the latest key automatically from the cloned repo.');
440
+ console.log(' You never need to manage it — just keep the repo up to date (git pull).');
343
441
  console.log('');
344
- console.log(`Joined team ${teamId}.`);
442
+ console.log('Next: bind your repos to this team with:');
443
+ console.log(` wayfind context bind ${teamId} (run from each repo you work in)`);
345
444
 
445
+ if (existing) {
446
+ console.log('');
447
+ console.log(` (Updated existing registration for team ${teamId})`);
448
+ }
449
+
450
+ // Register profile in team directory
346
451
  const profile = readJSONFile(PROFILE_FILE);
347
452
  if (profile) {
348
453
  syncMemberToRegistry(profile, teamId);
349
454
  await announceToSlack(profile, teamId);
350
455
  } else {
351
- console.log(" Run 'wayfind whoami --setup' to register in the team directory.");
456
+ console.log('');
457
+ console.log("Run 'wayfind whoami --setup' to register your profile in the team directory.");
352
458
  }
353
459
  console.log('');
354
460
  }
@@ -3549,9 +3655,20 @@ function contextAdd(args) {
3549
3655
  const config = readContextConfig();
3550
3656
  if (!config.teams) config.teams = {};
3551
3657
 
3552
- // Try to read team name from the repo's wayfind.json
3553
- const sharedConfig = readJSONFile(path.join(resolved, 'wayfind.json')) || {};
3658
+ // Read and update wayfind.json in the repo — write team_id/team_name so joiners
3659
+ // can read them without needing to know the ID out of band
3660
+ const sharedConfigPath = path.join(resolved, 'wayfind.json');
3661
+ const sharedConfig = readJSONFile(sharedConfigPath) || {};
3554
3662
  const teamName = sharedConfig.team_name || teamId;
3663
+ if (!sharedConfig.team_id || !sharedConfig.team_name) {
3664
+ sharedConfig.team_id = teamId;
3665
+ sharedConfig.team_name = teamName;
3666
+ try {
3667
+ fs.writeFileSync(sharedConfigPath, JSON.stringify(sharedConfig, null, 2) + '\n');
3668
+ } catch (err) {
3669
+ console.error(`Warning: could not write wayfind.json: ${err.message}`);
3670
+ }
3671
+ }
3555
3672
 
3556
3673
  config.teams[teamId] = {
3557
3674
  path: resolved,
@@ -3566,6 +3683,23 @@ function contextAdd(args) {
3566
3683
  if (Object.keys(config.teams).length === 1) {
3567
3684
  console.log(' Set as default (only team).');
3568
3685
  }
3686
+
3687
+ // Generate first search API key if one doesn't exist yet
3688
+ const keyFile = path.join(resolved, '.wayfind-api-key');
3689
+ if (!fs.existsSync(keyFile)) {
3690
+ const key = crypto.randomBytes(32).toString('hex');
3691
+ try {
3692
+ fs.writeFileSync(keyFile, key + '\n', 'utf8');
3693
+ // Resolve token for git push (CLI context — use gh CLI)
3694
+ const token = detectGitHubToken();
3695
+ if (token && !process.env.GITHUB_TOKEN) process.env.GITHUB_TOKEN = token;
3696
+ pushApiKey(resolved);
3697
+ console.log(' Generated initial search API key → committed to team repo.');
3698
+ console.log(' Teammates who join will read it automatically. It rotates daily.');
3699
+ } catch (err) {
3700
+ console.error(` Warning: could not generate API key: ${err.message}`);
3701
+ }
3702
+ }
3569
3703
  }
3570
3704
 
3571
3705
  function contextBind(args) {
@@ -5932,8 +6066,8 @@ function showHelp() {
5932
6066
  console.log(' /doctor Check installation health');
5933
6067
  console.log('');
5934
6068
  console.log('Team setup:');
5935
- console.log(' wayfind team create Create a new team');
5936
- console.log(' wayfind team join <id> Join an existing team');
6069
+ console.log(' wayfind team create Create a new team');
6070
+ console.log(' wayfind team join <repo-url-or-path> Join an existing team');
5937
6071
  console.log(' wayfind team status Show current team info');
5938
6072
  console.log(' wayfind whoami Show your profile');
5939
6073
  console.log(' wayfind whoami --setup Set up your profile and personas');
package/doctor.sh CHANGED
@@ -275,9 +275,7 @@ check_team_context_freshness() {
275
275
 
276
276
  # Find team-context path via wayfind CLI
277
277
  local TEAM_PATH=""
278
- if [ -f "$HOME/repos/greg/wayfind/bin/team-context.js" ]; then
279
- TEAM_PATH=$(node "$HOME/repos/greg/wayfind/bin/team-context.js" context show 2>/dev/null | grep 'Path:' | head -1 | sed 's/.*Path: *//' || true)
280
- elif command -v wayfind >/dev/null 2>&1; then
278
+ if command -v wayfind >/dev/null 2>&1; then
281
279
  TEAM_PATH=$(wayfind context show 2>/dev/null | grep 'Path:' | head -1 | sed 's/.*Path: *//' || true)
282
280
  fi
283
281
 
@@ -337,9 +335,7 @@ check_team_versions() {
337
335
 
338
336
  # Check min_version from check-version command output
339
337
  local CHECK_OUTPUT=""
340
- if [ -f "$HOME/repos/greg/wayfind/bin/team-context.js" ]; then
341
- CHECK_OUTPUT=$(node "$HOME/repos/greg/wayfind/bin/team-context.js" check-version 2>&1 || true)
342
- elif command -v wayfind >/dev/null 2>&1; then
338
+ if command -v wayfind >/dev/null 2>&1; then
343
339
  CHECK_OUTPUT=$(wayfind check-version 2>&1 || true)
344
340
  fi
345
341
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wayfind",
3
- "version": "2.0.46",
3
+ "version": "2.0.48",
4
4
  "description": "Team decision trail for AI-assisted development. The connective tissue between product, engineering, and strategy.",
5
5
  "bin": {
6
6
  "wayfind": "./bin/team-context.js",
@@ -19,7 +19,6 @@ fi
19
19
  WAYFIND="$(command -v wayfind 2>/dev/null || echo "")"
20
20
  if [ -z "$WAYFIND" ]; then
21
21
  for candidate in \
22
- "$HOME/repos/greg/wayfind/bin/team-context.js" \
23
22
  "$HOME/repos/wayfind/bin/team-context.js"; do
24
23
  if [ -f "$candidate" ]; then
25
24
  WAYFIND="node $candidate"
@@ -10,7 +10,6 @@ WAYFIND="$(command -v wayfind 2>/dev/null || echo "")"
10
10
  if [ -z "$WAYFIND" ]; then
11
11
  # Try common local checkout paths
12
12
  for candidate in \
13
- "$HOME/repos/greg/wayfind/bin/team-context.js" \
14
13
  "$HOME/repos/wayfind/bin/team-context.js"; do
15
14
  if [ -f "$candidate" ]; then
16
15
  WAYFIND="node $candidate"
@@ -32,14 +32,14 @@ bash ~/.claude/team-context/journal-summary.sh --dir ~/.ai-memory/memory/journal
32
32
 
33
33
  ## Step 2: If journal-summary.sh is not installed
34
34
 
35
- Run setup.sh with `--update` to install it:
35
+ Run `wayfind update` to install it:
36
36
  ```bash
37
- bash ~/repos/greg/wayfind/setup.sh --tool claude-code --update
37
+ wayfind update
38
38
  ```
39
39
 
40
- Or install manually:
40
+ Or install manually from the npm package:
41
41
  ```bash
42
- cp ~/repos/greg/wayfind/journal-summary.sh ~/.claude/team-context/journal-summary.sh
42
+ cp "$(npm root -g)/wayfind/journal-summary.sh" ~/.claude/team-context/journal-summary.sh
43
43
  chmod +x ~/.claude/team-context/journal-summary.sh
44
44
  ```
45
45
 
@@ -10,15 +10,9 @@ Show a daily standup summary from journals and state files.
10
10
 
11
11
  ```bash
12
12
  # Current repo only (default)
13
- node ~/repos/greg/wayfind/bin/team-context.js standup
13
+ wayfind standup
14
14
 
15
15
  # All repos
16
- node ~/repos/greg/wayfind/bin/team-context.js standup --all
17
- ```
18
-
19
- If the local checkout isn't available:
20
- ```bash
21
- wayfind standup
22
16
  wayfind standup --all
23
17
  ```
24
18
 
@@ -9,12 +9,8 @@
9
9
 
10
10
  set -euo pipefail
11
11
 
12
- # Use local wayfind checkout if available, otherwise try npx
13
- WAYFIND_BIN="$HOME/repos/greg/wayfind/bin/team-context.js"
14
- if [ -f "$WAYFIND_BIN" ]; then
15
- node "$WAYFIND_BIN" status --write --quiet 2>/dev/null || true
16
- node "$WAYFIND_BIN" check-version 2>/dev/null || true
17
- elif command -v wayfind >/dev/null 2>&1; then
12
+ # Use installed wayfind CLI
13
+ if command -v wayfind >/dev/null 2>&1; then
18
14
  wayfind status --write --quiet 2>/dev/null || true
19
15
  wayfind check-version 2>/dev/null || true
20
16
  fi