indelible-mcp 4.0.0 → 4.1.0

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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/index.js +257 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "indelible-mcp",
3
- "version": "4.0.0",
3
+ "version": "4.1.0",
4
4
  "description": "Blockchain-backed memory and code storage for Claude Code. Save AI conversations and source code permanently on BSV.",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
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.0.0)
259
+ Indelible MCP — Blockchain memory for Claude Code (v4.1.0)
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.0.0',
471
+ version: '4.1.0',
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
- printHelp()
1022
+ runWizard().catch(e => { console.error('Error:', e.message); process.exit(1) })
769
1023
  }