anticode-node 0.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.
package/bin/cli.js ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+ require = require("esm")(module);
3
+ require("dotenv").config({ path: require("path").join(process.cwd(), ".env.local") });
4
+ require("dotenv").config({ path: require("path").join(process.cwd(), ".env") });
5
+ require("../index.ts");
package/index.ts ADDED
@@ -0,0 +1,119 @@
1
+ import * as fs from 'fs'
2
+ import * as path from 'path'
3
+ import { startNodeDaemon, stopNodeDaemon, getDaemonStatus } from './node-daemon'
4
+
5
+ const NODE_ID_FILE = path.join(process.cwd(), 'data', 'node-identity.json')
6
+ const API_BASE = process.env.NODE_REGISTRY_URL || 'https://antigravity-connect-ia.vercel.app/api/nodes'
7
+
8
+ function loadIdentity(): { nodeId: string; secret: string } | null {
9
+ try {
10
+ if (fs.existsSync(NODE_ID_FILE)) return JSON.parse(fs.readFileSync(NODE_ID_FILE, 'utf-8'))
11
+ } catch {}
12
+ return null
13
+ }
14
+
15
+ function saveIdentity(id: { nodeId: string; secret: string }) {
16
+ const dir = path.dirname(NODE_ID_FILE)
17
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true })
18
+ fs.writeFileSync(NODE_ID_FILE, JSON.stringify(id, null, 2))
19
+ }
20
+
21
+ function generateId(): string {
22
+ const chars = 'abcdefghijklmnopqrstuvwxyz0123456789'
23
+ let id = ''
24
+ for (let i = 0; i < 16; i++) id += chars[Math.floor(Math.random() * chars.length)]
25
+ return id
26
+ }
27
+
28
+ async function cmdJoin() {
29
+ const existing = loadIdentity()
30
+ if (existing) {
31
+ console.log(`Already registered as node: ${existing.nodeId}`)
32
+ return
33
+ }
34
+ const nodeId = generateId()
35
+ const secret = generateId() + generateId()
36
+ try {
37
+ const res = await fetch(`${API_BASE}/register`, {
38
+ method: 'POST',
39
+ headers: { 'Content-Type': 'application/json' },
40
+ body: JSON.stringify({
41
+ nodeId,
42
+ secret,
43
+ hostname: require('os').hostname(),
44
+ platform: process.platform,
45
+ version: require('../package.json').version,
46
+ }),
47
+ })
48
+ if (!res.ok) {
49
+ const err = await res.text()
50
+ console.error(`Registration failed: ${err}`)
51
+ return
52
+ }
53
+ saveIdentity({ nodeId, secret })
54
+ console.log(`Node registered: ${nodeId}`)
55
+ console.log(`Secret saved to: ${NODE_ID_FILE}`)
56
+ } catch (e: any) {
57
+ console.error(`Cannot reach registry (${API_BASE}): ${e.message}`)
58
+ console.log('Creating local-only node identity...')
59
+ saveIdentity({ nodeId, secret })
60
+ console.log(`Local node ID: ${nodeId}`)
61
+ }
62
+ }
63
+
64
+ async function cmdStart() {
65
+ const identity = loadIdentity()
66
+ if (!identity) {
67
+ console.log('Not registered. Run: anticode-node join')
68
+ return
69
+ }
70
+ const port = parseInt(process.env.NODE_PORT || '0') || 0
71
+ startNodeDaemon(identity, API_BASE, port)
72
+ }
73
+
74
+ function cmdStatus() {
75
+ const identity = loadIdentity()
76
+ if (!identity) {
77
+ console.log('Not registered')
78
+ console.log('Run: anticode-node join')
79
+ return
80
+ }
81
+ console.log(`Node ID: ${identity.nodeId}`)
82
+ console.log(`Status: ${getDaemonStatus()}`)
83
+ }
84
+
85
+ function cmdStop() {
86
+ stopNodeDaemon()
87
+ }
88
+
89
+ function cmdHelp() {
90
+ console.log(`
91
+ anticode-node — AGIC Network Node
92
+
93
+ Commands:
94
+ join Register this machine as an AGIC network node
95
+ start Start the node daemon (heartbeat every 60s)
96
+ status Show node registration and daemon status
97
+ stop Stop the node daemon
98
+ help Show this help
99
+ `)
100
+ }
101
+
102
+ const cmd = process.argv[2] || 'help'
103
+ switch (cmd) {
104
+ case 'join':
105
+ cmdJoin()
106
+ break
107
+ case 'start':
108
+ cmdStart()
109
+ break
110
+ case 'status':
111
+ cmdStatus()
112
+ break
113
+ case 'stop':
114
+ cmdStop()
115
+ break
116
+ default:
117
+ cmdHelp()
118
+ break
119
+ }
package/node-daemon.ts ADDED
@@ -0,0 +1,70 @@
1
+ const HEARTBEAT_INTERVAL = 60_000
2
+ let intervalHandle: ReturnType<typeof setInterval> | null = null
3
+ let running = false
4
+
5
+ interface NodeIdentity {
6
+ nodeId: string
7
+ secret: string
8
+ }
9
+
10
+ async function sendHeartbeat(identity: NodeIdentity, apiBase: string, services: string[]) {
11
+ try {
12
+ const payload = {
13
+ nodeId: identity.nodeId,
14
+ secret: identity.secret,
15
+ uptime: process.uptime(),
16
+ services,
17
+ timestamp: Date.now(),
18
+ }
19
+ const res = await fetch(`${apiBase}/heartbeat`, {
20
+ method: 'POST',
21
+ headers: { 'Content-Type': 'application/json' },
22
+ body: JSON.stringify(payload),
23
+ })
24
+ if (!res.ok) {
25
+ const err = await res.text()
26
+ console.error(`Heartbeat failed: ${err}`)
27
+ }
28
+ } catch (e: any) {
29
+ // Registry unreachable — daemon continues running locally
30
+ console.error(`Registry unreachable: ${e.message}`)
31
+ }
32
+ }
33
+
34
+ export function startNodeDaemon(identity: NodeIdentity, apiBase: string, port: number) {
35
+ if (running) {
36
+ console.log('Daemon already running')
37
+ return
38
+ }
39
+ running = true
40
+ const services: string[] = []
41
+ if (port > 0) services.push(`mcp:${port}`)
42
+
43
+ console.log(`Node daemon started (interval: ${HEARTBEAT_INTERVAL / 1000}s)`)
44
+ console.log(`Press Ctrl+C to stop`)
45
+
46
+ sendHeartbeat(identity, apiBase, services)
47
+ intervalHandle = setInterval(() => sendHeartbeat(identity, apiBase, services), HEARTBEAT_INTERVAL)
48
+
49
+ process.on('SIGINT', () => {
50
+ stopNodeDaemon()
51
+ process.exit(0)
52
+ })
53
+ process.on('SIGTERM', () => {
54
+ stopNodeDaemon()
55
+ process.exit(0)
56
+ })
57
+ }
58
+
59
+ export function stopNodeDaemon() {
60
+ if (intervalHandle) {
61
+ clearInterval(intervalHandle)
62
+ intervalHandle = null
63
+ }
64
+ running = false
65
+ console.log('Node daemon stopped')
66
+ }
67
+
68
+ export function getDaemonStatus(): string {
69
+ return running ? 'running' : 'stopped'
70
+ }
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "anticode-node",
3
+ "version": "0.1.0",
4
+ "description": "AGIC Network Node Client — run a node, earn AGIC rewards for uptime. Join the sovereign agent network.",
5
+ "bin": {
6
+ "anticode-node": "./bin/cli.js"
7
+ },
8
+ "files": [
9
+ "bin/",
10
+ "*.ts",
11
+ "README.md"
12
+ ],
13
+ "keywords": [
14
+ "agic",
15
+ "node",
16
+ "network",
17
+ "decentralized",
18
+ "blockchain",
19
+ "agent",
20
+ "autonomous",
21
+ "web3"
22
+ ],
23
+ "author": "Antigravity Connect IA",
24
+ "license": "MIT",
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "https://github.com/josemiguel3125-sketch/live-agent-os-infra"
28
+ },
29
+ "engines": {
30
+ "node": ">=18"
31
+ }
32
+ }