indelible-mcp 4.0.0 → 4.1.1
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/package.json +1 -1
- package/src/index.js +257 -3
- package/src/lib/spv.js +1 -1
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
15
|
import { createInterface } from 'node:readline'
|
|
16
|
+
import { execSync } from 'node:child_process'
|
|
16
17
|
import { homedir } from 'node:os'
|
|
17
18
|
import { join } from 'node:path'
|
|
18
19
|
import { readFileSync, writeFileSync, existsSync, mkdirSync, readdirSync, statSync } from 'node:fs'
|
|
@@ -30,6 +31,7 @@ import { updateVaultIndex } from './tools/update_vault_index.js'
|
|
|
30
31
|
import { diaryConnect } from './tools/diary_connect.js'
|
|
31
32
|
import { diaryChat } from './tools/diary_chat.js'
|
|
32
33
|
import { diarySave } from './tools/diary_save.js'
|
|
34
|
+
import * as spv from './lib/spv.js'
|
|
33
35
|
|
|
34
36
|
const CONTEXT_FILE = join(homedir(), '.indelible', 'indelible-context.jsonl')
|
|
35
37
|
|
|
@@ -254,7 +256,7 @@ Commands:
|
|
|
254
256
|
|
|
255
257
|
function printHelp() {
|
|
256
258
|
console.log(`
|
|
257
|
-
Indelible MCP — Blockchain memory for Claude Code (v4.
|
|
259
|
+
Indelible MCP — Blockchain memory for Claude Code (v4.1.1)
|
|
258
260
|
|
|
259
261
|
Setup:
|
|
260
262
|
indelible-mcp setup --wif=KEY --pin=PIN Import and encrypt your private key
|
|
@@ -466,7 +468,7 @@ function readStdin() {
|
|
|
466
468
|
|
|
467
469
|
const SERVER_INFO = {
|
|
468
470
|
name: 'indelible',
|
|
469
|
-
version: '4.
|
|
471
|
+
version: '4.1.1',
|
|
470
472
|
description: 'Blockchain-backed memory and code storage for Claude Code'
|
|
471
473
|
}
|
|
472
474
|
|
|
@@ -732,6 +734,258 @@ async function runMcpServer() {
|
|
|
732
734
|
}
|
|
733
735
|
}
|
|
734
736
|
|
|
737
|
+
// ============ SETUP WIZARD ============
|
|
738
|
+
|
|
739
|
+
async function runWizard() {
|
|
740
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout })
|
|
741
|
+
const ask = (q) => new Promise(resolve => rl.question(q, resolve))
|
|
742
|
+
|
|
743
|
+
console.log('\n Welcome to Indelible!\n')
|
|
744
|
+
console.log(' This wizard will set everything up for you.\n')
|
|
745
|
+
|
|
746
|
+
// Check existing config — run health check or resume wizard
|
|
747
|
+
let config = null
|
|
748
|
+
try { config = await loadConfig() } catch {}
|
|
749
|
+
|
|
750
|
+
if (config && config.address) {
|
|
751
|
+
// Run health check
|
|
752
|
+
console.log(' Checking your setup...\n')
|
|
753
|
+
let allGood = true
|
|
754
|
+
|
|
755
|
+
// Claude Code
|
|
756
|
+
try {
|
|
757
|
+
execSync('claude --version', { stdio: 'pipe' })
|
|
758
|
+
console.log(' ✓ Claude Code installed')
|
|
759
|
+
} catch {
|
|
760
|
+
console.log(' ✗ Claude Code not found')
|
|
761
|
+
allGood = false
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
// MCP registered
|
|
765
|
+
const claudeSettings = join(homedir(), '.claude', 'settings.json')
|
|
766
|
+
let mcpOk = false
|
|
767
|
+
try {
|
|
768
|
+
const s = JSON.parse(readFileSync(claudeSettings, 'utf8'))
|
|
769
|
+
mcpOk = !!s?.mcpServers?.indelible
|
|
770
|
+
} catch {}
|
|
771
|
+
console.log(mcpOk ? ' ✓ MCP registered with Claude Code' : ' ✗ MCP not registered')
|
|
772
|
+
if (!mcpOk) allGood = false
|
|
773
|
+
|
|
774
|
+
// Hooks installed
|
|
775
|
+
const hooksPath = join(homedir(), '.claude', 'settings.local.json')
|
|
776
|
+
let hooksOk = false
|
|
777
|
+
try {
|
|
778
|
+
const s = JSON.parse(readFileSync(hooksPath, 'utf8'))
|
|
779
|
+
hooksOk = s?.hooks?.PreCompact?.some(h =>
|
|
780
|
+
h.hooks?.some(hh => hh.command?.includes('indelible-mcp')) ||
|
|
781
|
+
h.command?.includes('indelible-mcp')
|
|
782
|
+
) && s?.hooks?.SessionStart?.some(h =>
|
|
783
|
+
h.hooks?.some(hh => hh.command?.includes('indelible-mcp')) ||
|
|
784
|
+
h.command?.includes('indelible-mcp')
|
|
785
|
+
)
|
|
786
|
+
} catch {}
|
|
787
|
+
console.log(hooksOk ? ' ✓ Auto-save hooks installed' : ' ✗ Auto-save hooks missing')
|
|
788
|
+
if (!hooksOk) allGood = false
|
|
789
|
+
|
|
790
|
+
// Wallet
|
|
791
|
+
console.log(` ✓ Wallet configured (${config.address})`)
|
|
792
|
+
|
|
793
|
+
// Funded
|
|
794
|
+
let funded = false
|
|
795
|
+
try {
|
|
796
|
+
const utxos = await spv.getUtxos(config.address)
|
|
797
|
+
if (utxos && utxos.length > 0) {
|
|
798
|
+
const total = utxos.reduce((sum, u) => sum + u.satoshis, 0)
|
|
799
|
+
console.log(` ✓ Wallet funded (${total} sats)`)
|
|
800
|
+
funded = true
|
|
801
|
+
} else {
|
|
802
|
+
console.log(' ✗ Wallet not funded')
|
|
803
|
+
allGood = false
|
|
804
|
+
}
|
|
805
|
+
} catch {
|
|
806
|
+
console.log(' ✗ Could not check balance')
|
|
807
|
+
allGood = false
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
// Style
|
|
811
|
+
const hasStyle = !!config.style_txid
|
|
812
|
+
console.log(hasStyle ? ' ✓ AI style saved' : ' ✗ No AI style chosen')
|
|
813
|
+
if (!hasStyle) allGood = false
|
|
814
|
+
|
|
815
|
+
// API reachable
|
|
816
|
+
try {
|
|
817
|
+
const res = await fetch('https://indelible.one/api/health')
|
|
818
|
+
console.log(res.ok ? ' ✓ API reachable' : ' ✗ API unreachable')
|
|
819
|
+
if (!res.ok) allGood = false
|
|
820
|
+
} catch {
|
|
821
|
+
console.log(' ✗ API unreachable')
|
|
822
|
+
allGood = false
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
console.log('')
|
|
826
|
+
|
|
827
|
+
if (allGood) {
|
|
828
|
+
console.log(' Everything looks good! Open Claude Code in VS Code and start coding.\n')
|
|
829
|
+
rl.close()
|
|
830
|
+
return
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
// Resume wizard at the right point
|
|
834
|
+
if (!funded) {
|
|
835
|
+
console.log(' Resuming setup — your wallet needs funding.\n')
|
|
836
|
+
// Fall through to balance polling below
|
|
837
|
+
} else if (!hasStyle) {
|
|
838
|
+
console.log(' Resuming setup — pick your AI style.\n')
|
|
839
|
+
// Skip to style selection (fall through, balance polling will pass instantly)
|
|
840
|
+
} else {
|
|
841
|
+
// Something else failed (hooks, MCP, etc) — try to fix
|
|
842
|
+
if (!mcpOk) {
|
|
843
|
+
console.log(' Fixing: registering MCP with Claude Code...')
|
|
844
|
+
try {
|
|
845
|
+
execSync('claude mcp add indelible -- indelible-mcp', { stdio: 'pipe' })
|
|
846
|
+
console.log(' ✓ MCP registered\n')
|
|
847
|
+
} catch {
|
|
848
|
+
console.log(' Run this yourself: claude mcp add indelible -- indelible-mcp\n')
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
if (!hooksOk) {
|
|
852
|
+
console.log(' Fixing: installing auto-save hooks...')
|
|
853
|
+
installHooks()
|
|
854
|
+
console.log(' ✓ Hooks installed\n')
|
|
855
|
+
}
|
|
856
|
+
rl.close()
|
|
857
|
+
return
|
|
858
|
+
}
|
|
859
|
+
} else {
|
|
860
|
+
// Fresh install — run full wizard
|
|
861
|
+
|
|
862
|
+
// Check for Claude Code
|
|
863
|
+
try {
|
|
864
|
+
execSync('claude --version', { stdio: 'pipe' })
|
|
865
|
+
console.log(' ✓ Claude Code found\n')
|
|
866
|
+
} catch {
|
|
867
|
+
console.log(' Claude Code not found. Installing...\n')
|
|
868
|
+
try {
|
|
869
|
+
execSync('npm install -g @anthropic-ai/claude-code', { stdio: 'inherit' })
|
|
870
|
+
console.log('\n ✓ Claude Code installed\n')
|
|
871
|
+
} catch {
|
|
872
|
+
console.log('\n Could not install Claude Code automatically.')
|
|
873
|
+
console.log(' Run this yourself: npm install -g @anthropic-ai/claude-code')
|
|
874
|
+
console.log(' Then run indelible-mcp again.\n')
|
|
875
|
+
rl.close()
|
|
876
|
+
return
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
// Ask for WIF
|
|
881
|
+
console.log(' Next: connect your wallet.\n')
|
|
882
|
+
console.log(' Go to https://indelible.one → Sign in → Settings → copy your Private Key (WIF)\n')
|
|
883
|
+
const wifInput = await ask(' Paste your WIF here: ')
|
|
884
|
+
if (!wifInput || !wifInput.trim()) {
|
|
885
|
+
console.log(' No WIF provided. Run indelible-mcp again when ready.\n')
|
|
886
|
+
rl.close()
|
|
887
|
+
return
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
// Ask for PIN
|
|
891
|
+
console.log('')
|
|
892
|
+
const pinInput = await ask(' Choose a PIN (min 4 characters — you\'ll need this to unlock): ')
|
|
893
|
+
if (!pinInput || pinInput.trim().length < 4) {
|
|
894
|
+
console.log(' PIN must be at least 4 characters. Run indelible-mcp again.\n')
|
|
895
|
+
rl.close()
|
|
896
|
+
return
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
// Run setupWallet
|
|
900
|
+
console.log('\n Setting up wallet...')
|
|
901
|
+
const result = await setupWallet(undefined, wifInput.trim(), pinInput.trim())
|
|
902
|
+
if (!result.success) {
|
|
903
|
+
console.log(` Error: ${result.error || result.message}\n`)
|
|
904
|
+
rl.close()
|
|
905
|
+
return
|
|
906
|
+
}
|
|
907
|
+
console.log(' ✓ Wallet configured\n')
|
|
908
|
+
|
|
909
|
+
// Register MCP with Claude Code
|
|
910
|
+
console.log(' Registering Indelible with Claude Code...')
|
|
911
|
+
try {
|
|
912
|
+
execSync('claude mcp add indelible -- indelible-mcp', { stdio: 'pipe' })
|
|
913
|
+
console.log(' ✓ MCP registered\n')
|
|
914
|
+
} catch {
|
|
915
|
+
console.log(' Could not register automatically.')
|
|
916
|
+
console.log(' Run this yourself: claude mcp add indelible -- indelible-mcp\n')
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
config = await loadConfig()
|
|
920
|
+
}
|
|
921
|
+
// Check if already funded — skip polling if so
|
|
922
|
+
let alreadyFunded = false
|
|
923
|
+
try {
|
|
924
|
+
const utxos = await spv.getUtxos(config.address)
|
|
925
|
+
if (utxos && utxos.length > 0) alreadyFunded = true
|
|
926
|
+
} catch {}
|
|
927
|
+
|
|
928
|
+
if (!alreadyFunded) {
|
|
929
|
+
console.log(` Your BSV address: ${config.address}`)
|
|
930
|
+
console.log(' Send BSV to this address to fund your wallet.')
|
|
931
|
+
console.log(' Each save costs less than $0.01 — even $1 gets you hundreds of saves.\n')
|
|
932
|
+
console.log(' Waiting for funds...')
|
|
933
|
+
|
|
934
|
+
while (true) {
|
|
935
|
+
try {
|
|
936
|
+
const utxos = await spv.getUtxos(config.address)
|
|
937
|
+
if (utxos && utxos.length > 0) {
|
|
938
|
+
const total = utxos.reduce((sum, u) => sum + u.satoshis, 0)
|
|
939
|
+
console.log(`\n ✓ Funded! Balance: ${total} sats\n`)
|
|
940
|
+
break
|
|
941
|
+
}
|
|
942
|
+
} catch {}
|
|
943
|
+
await new Promise(r => setTimeout(r, 10000))
|
|
944
|
+
process.stdout.write('.')
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
// Choose AI style — skip if already saved
|
|
949
|
+
if (!config.style_txid) {
|
|
950
|
+
console.log(' Last step — choose how your AI behaves:\n')
|
|
951
|
+
console.log(' 1. Strict — Confirm everything. Never assume. Never get creative.')
|
|
952
|
+
console.log(' 2. Collaborative — Suggest ideas but wait for approval before coding.')
|
|
953
|
+
console.log(' 3. Autonomous — Move fast. Fix what you see. Commit when ready.\n')
|
|
954
|
+
|
|
955
|
+
const styleChoice = await ask(' Pick 1, 2, or 3 (recommended: 1): ')
|
|
956
|
+
const styleMap = { '1': 'strict', '2': 'collaborative', '3': 'autonomous' }
|
|
957
|
+
const styleName = styleMap[styleChoice?.trim()] || 'strict'
|
|
958
|
+
|
|
959
|
+
console.log(`\n Saving "${styleName}" style to blockchain...`)
|
|
960
|
+
try {
|
|
961
|
+
const presetRes = await fetch('https://indelible.one/api/styles/presets/' + styleName)
|
|
962
|
+
if (presetRes.ok) {
|
|
963
|
+
const preset = await presetRes.json()
|
|
964
|
+
const rulesText = preset.rules.map((r, i) => `${i + 1}. ${r}`).join('\n')
|
|
965
|
+
const styleResult = await saveStyle(rulesText, preset.name, preset.description)
|
|
966
|
+
if (styleResult.success) {
|
|
967
|
+
console.log(` ✓ Style saved to blockchain (tx: ${styleResult.txId.slice(0, 8)}...)\n`)
|
|
968
|
+
} else {
|
|
969
|
+
console.log(` Warning: ${styleResult.error}\n`)
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
} catch (e) {
|
|
973
|
+
console.log(` Warning: Could not save style — ${e.message}\n`)
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
console.log(' =========================================')
|
|
978
|
+
console.log(' You\'re all set! Open Claude Code in VS Code and start coding.')
|
|
979
|
+
console.log('')
|
|
980
|
+
console.log(' Quick commands to tell your AI:')
|
|
981
|
+
console.log(' "Save this session to blockchain"')
|
|
982
|
+
console.log(' "Load my previous context"')
|
|
983
|
+
console.log(' "Delta save"')
|
|
984
|
+
console.log(' =========================================\n')
|
|
985
|
+
|
|
986
|
+
rl.close()
|
|
987
|
+
}
|
|
988
|
+
|
|
735
989
|
// ============ MAIN ============
|
|
736
990
|
|
|
737
991
|
const args = process.argv.slice(2)
|
|
@@ -765,5 +1019,5 @@ Add this to your Claude Code settings.json:
|
|
|
765
1019
|
// No args, piped stdin = MCP server mode
|
|
766
1020
|
runMcpServer().catch(console.error)
|
|
767
1021
|
} else {
|
|
768
|
-
|
|
1022
|
+
runWizard().catch(e => { console.error('Error:', e.message); process.exit(1) })
|
|
769
1023
|
}
|
package/src/lib/spv.js
CHANGED
|
@@ -20,7 +20,7 @@ const SEED_BRIDGES = [
|
|
|
20
20
|
// Old individual bridge IPs — used to detect configs that need migration
|
|
21
21
|
const OLD_BRIDGE_IPS = [
|
|
22
22
|
'45.76.19.199', '107.191.49.18', '155.138.254.224',
|
|
23
|
-
'144.202.50.135', '155.138.216.126'
|
|
23
|
+
'144.202.50.135', '155.138.216.126', '155.138.238.167'
|
|
24
24
|
]
|
|
25
25
|
|
|
26
26
|
// Bridge health tracking
|