clew-code 0.2.28 → 0.2.30

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 (52) hide show
  1. package/README.md +38 -28
  2. package/bin/clew.cjs +2 -2
  3. package/dist/main.js +2318 -2331
  4. package/docs/architecture.html +90 -91
  5. package/docs/changelog.html +141 -150
  6. package/docs/cli-reference.html +89 -90
  7. package/docs/commands.html +10 -9
  8. package/docs/daemon.html +62 -62
  9. package/docs/generated/providers.html +625 -0
  10. package/docs/generated/tools.html +559 -0
  11. package/docs/index.html +10 -13
  12. package/docs/personal-profile.html +3 -3
  13. package/docs/providers.html +625 -87
  14. package/docs/quick-start.html +81 -81
  15. package/docs/tools.html +551 -175
  16. package/docs/troubleshooting.html +86 -86
  17. package/package.json +165 -165
  18. package/scripts/auto-close-duplicates.ts +277 -0
  19. package/scripts/backfill-duplicate-comments.ts +213 -0
  20. package/scripts/codegraph.ts +221 -0
  21. package/scripts/comment-on-duplicates.sh +95 -0
  22. package/scripts/edit-issue-labels.sh +84 -0
  23. package/scripts/final-peer-rename.mjs +46 -0
  24. package/scripts/fix-encoding.mjs +83 -0
  25. package/scripts/fix-inconsistencies.mjs +67 -0
  26. package/scripts/generate-docs.ts +307 -0
  27. package/scripts/gh.sh +96 -0
  28. package/scripts/install.ps1 +37 -0
  29. package/scripts/install.sh +49 -0
  30. package/scripts/issue-lifecycle.ts +38 -0
  31. package/scripts/lifecycle-comment.ts +53 -0
  32. package/scripts/normalize-html.mjs +37 -0
  33. package/scripts/preload.ts +159 -0
  34. package/scripts/rename-content-peer-to-swarm.mjs +67 -0
  35. package/scripts/rename-hooks-mesh.mjs +6 -0
  36. package/scripts/rename-peer-to-swarm.mjs +62 -0
  37. package/scripts/run_devcontainer_claude_code.ps1 +152 -0
  38. package/scripts/scrape.py +82 -0
  39. package/scripts/session.ts +195 -0
  40. package/scripts/sweep.ts +168 -0
  41. package/scripts/write-discovery-test.cjs +93 -0
  42. package/scripts/write-discovery-test2.cjs +65 -0
  43. package/scripts/write-server-final.cjs +108 -0
  44. package/scripts/write-server-test.cjs +69 -0
  45. package/scripts/write-server-test2.cjs +99 -0
  46. package/scripts/write-server-test3.cjs +59 -0
  47. package/scripts/write-server-test4.cjs +108 -0
  48. package/scripts/write-server-v2.cjs +142 -0
  49. package/scripts/write-server-v2b.cjs +129 -0
  50. package/scripts/write-server-v2c.cjs +136 -0
  51. package/scripts/write-store-test.cjs +12 -0
  52. package/scripts/write-store-test2.cjs +163 -0
package/scripts/gh.sh ADDED
@@ -0,0 +1,96 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ # Wrapper around gh CLI that only allows specific subcommands and flags.
5
+ # All commands are scoped to the current repository via GH_REPO or GITHUB_REPOSITORY.
6
+ #
7
+ # Usage:
8
+ # ./scripts/gh.sh issue view 123
9
+ # ./scripts/gh.sh issue view 123 --comments
10
+ # ./scripts/gh.sh issue list --state open --limit 20
11
+ # ./scripts/gh.sh search issues "search query" --limit 10
12
+ # ./scripts/gh.sh label list --limit 100
13
+
14
+ export GH_HOST=github.com
15
+
16
+ REPO="${GH_REPO:-${GITHUB_REPOSITORY:-}}"
17
+ if [[ -z "$REPO" || "$REPO" == */*/* || "$REPO" != */* ]]; then
18
+ echo "Error: GH_REPO or GITHUB_REPOSITORY must be set to owner/repo format (e.g., GITHUB_REPOSITORY=anthropics/claude-code)" >&2
19
+ exit 1
20
+ fi
21
+ export GH_REPO="$REPO"
22
+
23
+ ALLOWED_FLAGS=(--comments --state --limit --label)
24
+ FLAGS_WITH_VALUES=(--state --limit --label)
25
+
26
+ SUB1="${1:-}"
27
+ SUB2="${2:-}"
28
+ CMD="$SUB1 $SUB2"
29
+ case "$CMD" in
30
+ "issue view"|"issue list"|"search issues"|"label list")
31
+ ;;
32
+ *)
33
+ echo "Error: only 'issue view', 'issue list', 'search issues', 'label list' are allowed (e.g., ./scripts/gh.sh issue view 123)" >&2
34
+ exit 1
35
+ ;;
36
+ esac
37
+
38
+ shift 2
39
+
40
+ # Separate flags from positional arguments
41
+ POSITIONAL=()
42
+ FLAGS=()
43
+ skip_next=false
44
+ for arg in "$@"; do
45
+ if [[ "$skip_next" == true ]]; then
46
+ FLAGS+=("$arg")
47
+ skip_next=false
48
+ elif [[ "$arg" == -* ]]; then
49
+ flag="${arg%%=*}"
50
+ matched=false
51
+ for allowed in "${ALLOWED_FLAGS[@]}"; do
52
+ if [[ "$flag" == "$allowed" ]]; then
53
+ matched=true
54
+ break
55
+ fi
56
+ done
57
+ if [[ "$matched" == false ]]; then
58
+ echo "Error: only --comments, --state, --limit, --label flags are allowed (e.g., ./scripts/gh.sh issue list --state open --limit 20)" >&2
59
+ exit 1
60
+ fi
61
+ FLAGS+=("$arg")
62
+ # If flag expects a value and isn't using = syntax, skip next arg
63
+ if [[ "$arg" != *=* ]]; then
64
+ for vflag in "${FLAGS_WITH_VALUES[@]}"; do
65
+ if [[ "$flag" == "$vflag" ]]; then
66
+ skip_next=true
67
+ break
68
+ fi
69
+ done
70
+ fi
71
+ else
72
+ POSITIONAL+=("$arg")
73
+ fi
74
+ done
75
+
76
+ if [[ "$CMD" == "search issues" ]]; then
77
+ QUERY="${POSITIONAL[0]:-}"
78
+ QUERY_LOWER=$(echo "$QUERY" | tr '[:upper:]' '[:lower:]')
79
+ if [[ "$QUERY_LOWER" == *"repo:"* || "$QUERY_LOWER" == *"org:"* || "$QUERY_LOWER" == *"user:"* ]]; then
80
+ echo "Error: search query must not contain repo:, org:, or user: qualifiers (e.g., ./scripts/gh.sh search issues \"bug report\" --limit 10)" >&2
81
+ exit 1
82
+ fi
83
+ gh "$SUB1" "$SUB2" "$QUERY" --repo "$REPO" "${FLAGS[@]}"
84
+ elif [[ "$CMD" == "issue view" ]]; then
85
+ if [[ ${#POSITIONAL[@]} -ne 1 ]] || ! [[ "${POSITIONAL[0]}" =~ ^[0-9]+$ ]]; then
86
+ echo "Error: issue view requires exactly one numeric issue number (e.g., ./scripts/gh.sh issue view 123)" >&2
87
+ exit 1
88
+ fi
89
+ gh "$SUB1" "$SUB2" "${POSITIONAL[0]}" "${FLAGS[@]}"
90
+ else
91
+ if [[ ${#POSITIONAL[@]} -ne 0 ]]; then
92
+ echo "Error: issue list and label list do not accept positional arguments (e.g., ./scripts/gh.sh issue list --state open, ./scripts/gh.sh label list --limit 100)" >&2
93
+ exit 1
94
+ fi
95
+ gh "$SUB1" "$SUB2" "${FLAGS[@]}"
96
+ fi
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env pwsh
2
+ #Requires -PSEdition Desktop
3
+ #Requires -RunAsAdministrator
4
+
5
+ $ErrorActionPreference = 'Stop'
6
+
7
+ function Write-Info { Write-Host "✓ $($args -join ' ')" -ForegroundColor Green }
8
+ function Write-Warn { Write-Host "⚠ $($args -join ' ')" -ForegroundColor Yellow }
9
+ function Write-Error { Write-Host "✗ $($args -join ' ')" -ForegroundColor Red; exit 1 }
10
+
11
+ # ── Install bun if missing ───────────────────────────────────────────────────
12
+ if (-not (Get-Command bun -ErrorAction SilentlyContinue)) {
13
+ Write-Info 'Bun not found — installing...'
14
+ try {
15
+ $null = & powershell -NoProfile -Command "irm bun.sh/install.ps1 | iex" 2>&1
16
+ } catch {
17
+ Write-Error "Bun install failed: $($_.Exception.Message)"
18
+ }
19
+ # Refresh PATH so bun is available immediately
20
+ $env:Path = [Environment]::GetEnvironmentVariable('Path', 'User') +
21
+ ';' + [Environment]::GetEnvironmentVariable('Path', 'Machine')
22
+ if (-not (Get-Command bun -ErrorAction SilentlyContinue)) {
23
+ Write-Error 'Bun installed but not found in PATH. Restart your shell and try again.'
24
+ }
25
+ Write-Info "Bun $(& bun --version) installed"
26
+ } else {
27
+ Write-Info "Bun $(& bun --version) found"
28
+ }
29
+
30
+ # ── Install clew-code ───────────────────────────────────────────────────────
31
+ Write-Info 'Installing clew-code via bun...'
32
+ # --ignore-scripts skips sharp (from @xenova/transformers) install script,
33
+ # which fails on Node.js <14 or missing build tools. clew imports sharp
34
+ # dynamically — it's only needed for image/ComputerUse features.
35
+ & bun install -g clew-code --ignore-scripts
36
+
37
+ Write-Host "`nDone! Run clew to start." -ForegroundColor Green
@@ -0,0 +1,49 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ INSTALL_DIR="${INSTALL_DIR:-$HOME/.clew}"
5
+
6
+ # ── Colors ──────────────────────────────────────────────────────────────────
7
+ RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; BOLD='\033[1m'; NC='\033[0m'
8
+ info() { printf "${GREEN}✓${NC} %s\n" "$*"; }
9
+ warn() { printf "${YELLOW}⚠${NC} %s\n" "$*"; }
10
+ err() { printf "${RED}✗${NC} %s\n" "$*" >&2; }
11
+
12
+ # ── Platform ─────────────────────────────────────────────────────────────────
13
+ OS="$(uname -s)"
14
+ case "$OS" in
15
+ Darwin|Linux|MINGW*|CYGWIN*|MSYS*) ;;
16
+ *) err "Unsupported OS: $OS (use install.ps1 on Windows)"; exit 1 ;;
17
+ esac
18
+
19
+ # ── Install bun if missing ──────────────────────────────────────────────────
20
+ if ! command -v bun &>/dev/null; then
21
+ info "Bun not found — installing..."
22
+ case "$OS" in
23
+ Darwin|Linux)
24
+ curl -fsSL https://bun.sh/install | bash
25
+ # Source the updated profile so bun is in PATH for the rest of this script
26
+ export BUN_INSTALL="${BUN_INSTALL:-$HOME/.bun}"
27
+ if [ -f "$BUN_INSTALL/env" ]; then
28
+ # shellcheck source=/dev/null
29
+ source "$BUN_INSTALL/env"
30
+ fi
31
+ ;;
32
+ esac
33
+ if ! command -v bun &>/dev/null; then
34
+ err "Bun installed but not found in PATH. Restart your shell and try again."
35
+ exit 1
36
+ fi
37
+ info "Bun $(bun --version) installed"
38
+ else
39
+ info "Bun $(bun --version) found"
40
+ fi
41
+
42
+ # ── Install clew-code ───────────────────────────────────────────────────────
43
+ info "Installing clew-code via bun..."
44
+ # --ignore-scripts skips sharp (from @xenova/transformers) install script,
45
+ # which fails on Node.js <14 or missing build tools. clew imports sharp
46
+ # dynamically — it's only needed for image/ComputerUse features.
47
+ bun install -g clew-code --ignore-scripts
48
+
49
+ printf "\n${BOLD}Done!${NC} Run ${BOLD}clew${NC} to start.\n"
@@ -0,0 +1,38 @@
1
+ // Single source of truth for issue lifecycle labels, timeouts, and messages.
2
+
3
+ export const lifecycle = [
4
+ {
5
+ label: "invalid",
6
+ days: 3,
7
+ reason: "this doesn't appear to be about Claude Code",
8
+ nudge: "This doesn't appear to be about [Claude Code](https://github.com/anthropics/claude-code). For general Anthropic support, visit [support.anthropic.com](https://support.anthropic.com).",
9
+ },
10
+ {
11
+ label: "needs-repro",
12
+ days: 7,
13
+ reason: "we still need reproduction steps to investigate",
14
+ nudge: "We weren't able to reproduce this. Could you provide steps to trigger the issue — what you ran, what happened, and what you expected?",
15
+ },
16
+ {
17
+ label: "needs-info",
18
+ days: 7,
19
+ reason: "we still need a bit more information to move forward",
20
+ nudge: "We need more information to continue investigating. Can you make sure to include your Claude Code version (`claude --version`), OS, and any error messages or logs?",
21
+ },
22
+ {
23
+ label: "stale",
24
+ days: 14,
25
+ reason: "inactive for too long",
26
+ nudge: "This issue has been automatically marked as stale due to inactivity.",
27
+ },
28
+ {
29
+ label: "autoclose",
30
+ days: 14,
31
+ reason: "inactive for too long",
32
+ nudge: "This issue has been marked for automatic closure.",
33
+ },
34
+ ] as const;
35
+
36
+ export type LifecycleLabel = (typeof lifecycle)[number]["label"];
37
+
38
+ export const STALE_UPVOTE_THRESHOLD = 10;
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env bun
2
+
3
+ // Posts a comment when a lifecycle label is applied to an issue,
4
+ // giving the author a heads-up and a chance to respond before auto-close.
5
+
6
+ import { lifecycle } from "./issue-lifecycle.ts";
7
+
8
+ const DRY_RUN = process.argv.includes("--dry-run");
9
+ const token = process.env.GITHUB_TOKEN;
10
+ const repo = process.env.GITHUB_REPOSITORY; // owner/repo
11
+ const label = process.env.LABEL;
12
+ const issueNumber = process.env.ISSUE_NUMBER;
13
+
14
+ if (!DRY_RUN && !token) throw new Error("GITHUB_TOKEN required");
15
+ if (!repo) throw new Error("GITHUB_REPOSITORY required");
16
+ if (!label) throw new Error("LABEL required");
17
+ if (!issueNumber) throw new Error("ISSUE_NUMBER required");
18
+
19
+ const entry = lifecycle.find((l) => l.label === label);
20
+ if (!entry) {
21
+ console.log(`No lifecycle entry for label "${label}", skipping`);
22
+ process.exit(0);
23
+ }
24
+
25
+ const body = `${entry.nudge} This issue will be closed automatically if there's no activity within ${entry.days} days.`;
26
+
27
+ // --
28
+
29
+ if (DRY_RUN) {
30
+ console.log(`Would comment on #${issueNumber} for label "${label}":\n\n${body}`);
31
+ process.exit(0);
32
+ }
33
+
34
+ const response = await fetch(
35
+ `https://api.github.com/repos/${repo}/issues/${issueNumber}/comments`,
36
+ {
37
+ method: "POST",
38
+ headers: {
39
+ Authorization: `Bearer ${token}`,
40
+ Accept: "application/vnd.github.v3+json",
41
+ "Content-Type": "application/json",
42
+ "User-Agent": "lifecycle-comment",
43
+ },
44
+ body: JSON.stringify({ body }),
45
+ }
46
+ );
47
+
48
+ if (!response.ok) {
49
+ const text = await response.text();
50
+ throw new Error(`GitHub API ${response.status}: ${text}`);
51
+ }
52
+
53
+ console.log(`Commented on #${issueNumber} for label "${label}"`);
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Normalize HTML structure: replace inline headers with JS-injected pattern.
3
+ */
4
+ import fs from 'node:fs';
5
+ import path from 'node:path';
6
+
7
+ const files = [
8
+ 'docs/features/swarm.html',
9
+ 'docs/internals/hidden-features.html',
10
+ 'docs/internals/hidden-features.th.html',
11
+ ];
12
+
13
+ for (const filePath of files) {
14
+ if (!fs.existsSync(filePath)) {
15
+ console.log('SKIP:', filePath);
16
+ continue;
17
+ }
18
+
19
+ let c = fs.readFileSync(filePath, 'utf-8');
20
+
21
+ // Remove inline header (full block between <header class="header"> and </header>)
22
+ c = c.replace(/<header class="header">[\s\S]*?<\/header>\n?/,
23
+ '<header class="header"></header>\n');
24
+
25
+ // Determine relative JS path
26
+ const dir = path.dirname(filePath);
27
+ const isSub = dir.includes('features') || dir.includes('internals');
28
+ const jsPath = isSub ? '../js/main.js' : 'js/main.js';
29
+
30
+ // Add script if missing
31
+ if (!c.includes('main.js')) {
32
+ c = c.replace('</body>', `<script src="${jsPath}"></script>\n</body>`);
33
+ }
34
+
35
+ fs.writeFileSync(filePath, c, 'utf-8');
36
+ console.log('Fixed:', filePath);
37
+ }
@@ -0,0 +1,159 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * Context Preloader
4
+ *
5
+ * Prepares module context before Claude Code starts editing.
6
+ * Usage: bun run scripts/preload.ts <module-name>
7
+ * bun run scripts/preload.ts src/bridge
8
+ * bun run scripts/preload.ts src/services/ai
9
+ */
10
+
11
+ import { readFileSync, writeFileSync, mkdirSync, readdirSync, statSync } from 'fs'
12
+ import { join, dirname, basename } from 'path'
13
+ import { execSync } from 'child_process'
14
+
15
+ const ROOT = join(import.meta.dirname, '..')
16
+ const SRC = join(ROOT, 'src')
17
+ const CONTEXT_DIR = join(ROOT, '.clew', 'context')
18
+
19
+ const moduleArg = process.argv[2]
20
+ if (!moduleArg) {
21
+ console.error('Usage: bun run scripts/preload.ts <module-path>')
22
+ console.error(' e.g. bun run scripts/preload.ts bridge')
23
+ console.error(' e.g. bun run scripts/preload.ts src/bridge')
24
+ process.exit(1)
25
+ }
26
+
27
+ const modPath = moduleArg.replace(/\\/g, '/').replace(/^src\//, '')
28
+ const targetDir = join(SRC, modPath)
29
+
30
+ function run(cmd: string): string {
31
+ try {
32
+ return execSync(cmd, { cwd: ROOT, encoding: 'utf-8', timeout: 15000, stdio: ['pipe', 'pipe', 'ignore'] })
33
+ } catch (e: any) {
34
+ return e.stdout || ''
35
+ }
36
+ }
37
+
38
+ function findFiles(dir: string): string[] {
39
+ try {
40
+ const entries = readdirSync(dir)
41
+ return entries
42
+ .filter(f => f.endsWith('.ts') || f.endsWith('.tsx'))
43
+ .map(f => join(dir, f))
44
+ .filter(f => statSync(f).isFile())
45
+ } catch {
46
+ return []
47
+ }
48
+ }
49
+
50
+ // ── Gather data ──
51
+ const files = findFiles(targetDir)
52
+
53
+ const md: string[] = []
54
+ md.push(`# Context: ${modPath}`)
55
+ md.push(`_Preloaded ${new Date().toISOString().slice(0, 16).replace('T', ' ')}_`)
56
+ md.push('')
57
+
58
+ // Summary
59
+ md.push(`## Scope`)
60
+ md.push('')
61
+ md.push(`Module: \`${modPath}\``)
62
+ md.push(`Files: ${files.length}`)
63
+ md.push('')
64
+
65
+ // File listing with sizes
66
+ md.push(`## Files`)
67
+ md.push('')
68
+ md.push(`| File | Lines | Exports | TODOs |`)
69
+ md.push(`|------|-------|---------|-------|`)
70
+
71
+ let totalLines = 0
72
+ for (const file of files) {
73
+ const relName = file.replace(/\\/g, '/').replace(ROOT.replace(/\\/g, '/') + '/', '')
74
+ const content = readFileSync(file, 'utf-8')
75
+ const lines = content.split('\n').length
76
+ totalLines += lines
77
+
78
+ const exports = content.match(/export (async )?(function|const|class|interface|type) [a-zA-Z_$][a-zA-Z0-9_$]*/g) || []
79
+ const exportList = exports.map(e => e.split(/\s+/).pop()).filter(Boolean).slice(0, 8).join(', ')
80
+ const todos = (content.match(/\bTODO|FIXME\b/g) || []).length
81
+
82
+ md.push(`| ${relName} | ${lines} | ${exportList || '-'} | ${todos || '-'} |`)
83
+ }
84
+
85
+ md.push(`| **Total** | **${totalLines}** | | |`)
86
+ md.push('')
87
+
88
+ // Internal dependencies
89
+ md.push(`## Internal Dependencies`)
90
+ md.push('')
91
+ md.push('```')
92
+ const deps = files.map(f => {
93
+ const c = readFileSync(f, 'utf-8')
94
+ return [...c.matchAll(/from\s+['"](src\/[^'"]+)['"]/g)].map(m => m[1])
95
+ }).flat()
96
+ const uniqueDeps = [...new Set(deps)].sort()
97
+ for (const d of uniqueDeps) md.push(d)
98
+ if (!uniqueDeps.length) md.push('(none)')
99
+ md.push('```')
100
+ md.push('')
101
+
102
+ // Recent git history
103
+ md.push(`## Recent Changes`)
104
+ md.push('')
105
+ md.push('```')
106
+ try {
107
+ const gitLog = run(`git log --oneline -10 -- "src/${modPath}/"`).trim()
108
+ md.push(gitLog || '(no recent changes)')
109
+ } catch {
110
+ md.push('(no git history)')
111
+ }
112
+ md.push('```')
113
+ md.push('')
114
+
115
+ // Key types
116
+ const typePattern = /export (interface|type) (\w+)/g
117
+ const allTypes: string[] = []
118
+ for (const file of files) {
119
+ const c = readFileSync(file, 'utf-8')
120
+ let m: RegExpExecArray | null
121
+ while ((m = typePattern.exec(c)) !== null) allTypes.push(m[2])
122
+ }
123
+ if (allTypes.length) {
124
+ md.push(`## Key Types`)
125
+ md.push('')
126
+ md.push('- ' + [...new Set(allTypes)].join('\n- '))
127
+ md.push('')
128
+ }
129
+
130
+ // Open TODOs
131
+ const allTodos: { file: string; line: string }[] = []
132
+ for (const file of files) {
133
+ const c = readFileSync(file, 'utf-8')
134
+ const lines = c.split('\n')
135
+ lines.forEach((l, i) => {
136
+ if (/\bTODO|FIXME\b/.test(l)) {
137
+ const text = l.replace(/^\s*\/\/\s*/, '').replace(/^\s*/, '').slice(0, 80)
138
+ allTodos.push({ file: file.replace(/\\/g, '/').replace(ROOT.replace(/\\/g, '/') + '/', ''), line: text })
139
+ }
140
+ })
141
+ }
142
+
143
+ if (allTodos.length) {
144
+ md.push(`## Open TODOs`)
145
+ md.push('')
146
+ for (const t of allTodos) md.push(`- \`${t.file}\`: ${t.line}`)
147
+ md.push('')
148
+ }
149
+
150
+ // Write
151
+ mkdirSync(CONTEXT_DIR, { recursive: true })
152
+ const outPath = join(CONTEXT_DIR, `${modPath.replace(/\//g, '-')}.md`)
153
+ writeFileSync(outPath, md.join('\n'), 'utf-8')
154
+
155
+ console.log(`\n✅ Preloaded: ${modPath}`)
156
+ console.log(` ${files.length} files, ${totalLines} lines`)
157
+ console.log(` Saved to: ${outPath}`)
158
+ console.log('')
159
+ console.log('Claude Code can now read this context via Read tool.')
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Content rename: peer -> swarm in all Swarm* tool files
3
+ */
4
+ import fs from 'node:fs';
5
+ import path from 'node:path';
6
+
7
+ function walk(dir) {
8
+ const r = [];
9
+ for (const e of fs.readdirSync(dir, { withFileTypes: true })) {
10
+ const f = path.join(dir, e.name);
11
+ if (e.isDirectory()) r.push(...walk(f));
12
+ else if (e.name.endsWith('.ts') || e.name.endsWith('.tsx')) r.push(f);
13
+ }
14
+ return r;
15
+ }
16
+
17
+ const dirs = [
18
+ 'src/tools/SwarmBroadcastTool',
19
+ 'src/tools/SwarmDisconnectTool',
20
+ 'src/tools/SwarmDiscoverTool',
21
+ 'src/tools/SwarmJoinTool',
22
+ 'src/tools/SwarmListMessagesTool',
23
+ 'src/tools/SwarmListRolesTool',
24
+ 'src/tools/SwarmPingTool',
25
+ 'src/tools/SwarmRunTool',
26
+ 'src/tools/SwarmSendMessageTool',
27
+ 'src/tools/SwarmSetNameTool',
28
+ 'src/tools/SwarmSetRoleTool',
29
+ 'src/tools/SwarmShareTool',
30
+ 'src/tools/SwarmSpawnTool',
31
+ 'src/tools/ProcessSwarmTool',
32
+ 'src/tools/CodexSwarmTool',
33
+ 'src/swarm',
34
+ ];
35
+
36
+ const files = [];
37
+ for (const d of dirs) {
38
+ if (fs.existsSync(d)) files.push(...walk(d));
39
+ }
40
+
41
+ for (const f of files) {
42
+ let c = fs.readFileSync(f, 'utf-8');
43
+ const orig = c;
44
+
45
+ // PeerXxx -> SwarmXxx (class/identifier names)
46
+ c = c.replace(/\bPeer(Broadcast|Disconnect|Discover|Join|ListMessages|ListRoles|Ping|Run|SendMessage|SetName|SetRole|Share|Spawn|Info|Help|Server|Store|Discovery|StatusLine)\b/g, 'Swarm$1');
47
+ c = c.replace(/\bProcessPeer(Provider|Tool)\b/g, 'ProcessSwarm$1');
48
+ c = c.replace(/\bCodexPeerTool\b/g, 'CodexSwarmTool');
49
+
50
+ // peer_xxx -> swarm_xxx (tool name constants)
51
+ c = c.replace(/peer_/g, 'swarm_');
52
+
53
+ // peerXxx -> swarmXxx (camelCase variables)
54
+ c = c.replace(/\bpeer(Server|Store|Discovery|Port|Name|Info|List|Count|Connection|Sharing|Health)\b/g, 'swarm$1');
55
+
56
+ // usePeerAutoInject -> useSwarmAutoInject
57
+ c = c.replace(/\busePeerAutoInject\b/g, 'useSwarmAutoInject');
58
+
59
+ // /peer -> /swarm (command paths)
60
+ c = c.replace(/\/peer\b/g, '/swarm');
61
+
62
+ if (c !== orig) {
63
+ fs.writeFileSync(f, c, 'utf-8');
64
+ console.log('OK:', f);
65
+ }
66
+ }
67
+ console.log('DONE');
@@ -0,0 +1,6 @@
1
+ import fs from 'fs';
2
+ for (const f of fs.readdirSync('src/hooks')) {
3
+ const nn = f.replace(/A2A/g, 'Mesh').replace(/a2a/g, 'mesh');
4
+ if (nn !== f) fs.renameSync('src/hooks/' + f, 'src/hooks/' + nn);
5
+ }
6
+ console.log('DONE');
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Bulk rename: peer -> swarm across all source files
3
+ */
4
+ import fs from 'node:fs';
5
+ import path from 'node:path';
6
+
7
+ function walk(dir) {
8
+ const results = [];
9
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
10
+ const full = path.join(dir, entry.name);
11
+ if (entry.isDirectory()) {
12
+ if (!entry.name.startsWith('.') && entry.name !== 'node_modules' && entry.name !== 'dist') {
13
+ results.push(...walk(full));
14
+ }
15
+ } else if (entry.name.endsWith('.ts') || entry.name.endsWith('.tsx')) {
16
+ results.push(full);
17
+ }
18
+ }
19
+ return results;
20
+ }
21
+
22
+ // Only replace import paths — safe, targeted changes
23
+ const replacements = [
24
+ // Import paths for peer/ directory
25
+ [/from ['"]\.\.\/peer\//g, `from '../swarm/`],
26
+ [/from ['"]\.\/peer\//g, `from './swarm/`],
27
+ [/from ['"]\.\.\/\.\.\/peer\//g, `from '../../swarm/`],
28
+ [/from ['"]\.\.\/\.\.\/\.\.\/peer\//g, `from '../../../swarm/`],
29
+
30
+ // Import paths for tools/Peer* -> tools/Swarm*
31
+ [/from ['"]\.\.\/\.\.\/tools\/PeerInfoTool\//g, `from '../../tools/SwarmInfoTool/`],
32
+ [/from ['"]\.\.\/tools\/PeerInfoTool\//g, `from '../tools/SwarmInfoTool/`],
33
+ [/from ['"]\.\/PeerInfoTool\//g, `from './SwarmInfoTool/`],
34
+ [/from ['"]\.\.\/\.\.\/tools\/PeerHelpTool\//g, `from '../../tools/SwarmHelpTool/`],
35
+ [/from ['"]\.\.\/tools\/PeerHelpTool\//g, `from '../tools/SwarmHelpTool/`],
36
+ [/from ['"]\.\/PeerHelpTool\//g, `from './SwarmHelpTool/`],
37
+ [/from ['"]\.\.\/peer\//g, `from '../swarm/`],
38
+ ];
39
+
40
+ const srcDir = 'src';
41
+ const files = walk(srcDir);
42
+ let totalChanged = 0;
43
+
44
+ for (const file of files) {
45
+ let content = fs.readFileSync(file, 'utf-8');
46
+ let changed = false;
47
+
48
+ for (const [pattern, replacement] of replacements) {
49
+ if (pattern.test(content)) {
50
+ content = content.replace(pattern, replacement);
51
+ changed = true;
52
+ }
53
+ }
54
+
55
+ if (changed) {
56
+ fs.writeFileSync(file, content, 'utf-8');
57
+ totalChanged++;
58
+ console.log('Updated:', file);
59
+ }
60
+ }
61
+
62
+ console.log(`\nTotal files updated: ${totalChanged}`);