@cortices/agent 0.4.23
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/README.md +104 -0
- package/bin/cortices-claude.mjs +29 -0
- package/bin/cortices-codex.mjs +29 -0
- package/bin/cortices-native.mjs +29 -0
- package/bin/cortices-opencode.mjs +29 -0
- package/bin/cortices.mjs +117 -0
- package/dist/claude-daemon.mjs +1 -0
- package/dist/codex-daemon.mjs +1 -0
- package/dist/cortices-daemon.mjs +1 -0
- package/dist/opencode-daemon.mjs +1 -0
- package/dist/scripts/memory.mjs +2 -0
- package/dist/scripts/notify.mjs +2 -0
- package/dist/scripts/plan.mjs +2 -0
- package/dist/scripts/schedule.mjs +2 -0
- package/dist/scripts/service.mjs +2 -0
- package/dist/sdk.mjs +1 -0
- package/dist/wasm/cortices_core.js +1 -0
- package/dist/wasm/cortices_core_bg.wasm +0 -0
- package/dist/wasm/package.json +1 -0
- package/package.json +53 -0
package/README.md
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# @cortices/agent
|
|
2
|
+
|
|
3
|
+
Connect your AI coding agents to [Cortices](https://cortices.io) — a real-time dashboard to monitor, chat with, and manage your agents from anywhere. Works behind NAT with no port forwarding needed.
|
|
4
|
+
|
|
5
|
+
## Supported Agents
|
|
6
|
+
|
|
7
|
+
| Agent | Type Flag | Requirement |
|
|
8
|
+
|-------|-----------|-------------|
|
|
9
|
+
| Claude Code | `--agent claude` (default) | [Claude Code CLI](https://docs.anthropic.com/en/docs/claude-code) |
|
|
10
|
+
| OpenAI Codex | `--agent codex` | [Codex CLI](https://github.com/openai/codex) |
|
|
11
|
+
|
|
12
|
+
## Quick Start
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
# Install globally
|
|
16
|
+
npm install -g @cortices/agent
|
|
17
|
+
|
|
18
|
+
# Run your agent (sign up at https://cortices.io for an API key)
|
|
19
|
+
cortices --api-key ck_your_key_here --dir ~/my-project
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Your agent appears in your [dashboard](https://cortices.io/dashboard) instantly.
|
|
23
|
+
|
|
24
|
+
## Options
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
--api-key KEY Your Cortices API key (required)
|
|
28
|
+
--dir DIR Working directory (default: current directory)
|
|
29
|
+
--name NAME Agent name shown in dashboard (default: directory name)
|
|
30
|
+
--agent TYPE Agent backend: claude (default), codex
|
|
31
|
+
--interactive Require approval for each tool call from the dashboard
|
|
32
|
+
--verbose, -v Show detailed debug logs
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Install as a Background Service
|
|
36
|
+
|
|
37
|
+
Run your agent as a persistent service that starts on boot and auto-restarts on failure. Requires **systemd** (Linux) or **launchd** (macOS).
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
# Install
|
|
41
|
+
cortices install --api-key ck_xxx --dir /path/to/project --name my-agent
|
|
42
|
+
|
|
43
|
+
# Manage
|
|
44
|
+
cortices list # List installed agents
|
|
45
|
+
cortices status NAME # Check agent status
|
|
46
|
+
cortices uninstall NAME # Remove agent
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Viewing Logs
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
# Linux
|
|
53
|
+
tail -f ~/.cortices/logs/NAME.log
|
|
54
|
+
|
|
55
|
+
# macOS
|
|
56
|
+
tail -f ~/Library/Logs/Cortices/NAME.log
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### No systemd/launchd?
|
|
60
|
+
|
|
61
|
+
If your system doesn't support systemd or launchd (e.g. containers, WSL1), run the agent directly in a tmux or screen session:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
tmux new -s my-agent
|
|
65
|
+
cortices --api-key ck_xxx --dir /path/to/project --name my-agent
|
|
66
|
+
# Ctrl+B, D to detach
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Note: without a service manager, restart and upgrade commands from the dashboard will disconnect the agent and it won't auto-restart. You'll need to manually re-run it.
|
|
70
|
+
|
|
71
|
+
## LLM Authentication
|
|
72
|
+
|
|
73
|
+
Configure your agent's LLM credentials from the dashboard **Vault** (lock icon on the agent page).
|
|
74
|
+
|
|
75
|
+
**Subscription login** — Use your existing Claude Pro/Max or ChatGPT Plus/Pro subscription. Log in on the agent machine first:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
# Claude Code
|
|
79
|
+
claude auth login
|
|
80
|
+
|
|
81
|
+
# Codex
|
|
82
|
+
codex login
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**API key** — Paste your key in the Vault. Supported providers depend on agent type:
|
|
86
|
+
|
|
87
|
+
| Agent | Providers |
|
|
88
|
+
|-------|-----------|
|
|
89
|
+
| Claude Code | Anthropic API, OpenRouter, AWS Bedrock, Custom |
|
|
90
|
+
| Codex | OpenAI API, OpenRouter, Custom |
|
|
91
|
+
|
|
92
|
+
## Permission Modes
|
|
93
|
+
|
|
94
|
+
- **Auto-approve (default)** — the agent executes tools automatically; you watch from the dashboard
|
|
95
|
+
- **Interactive (`--interactive`)** — every tool call requires your approval before it runs (Claude Code only)
|
|
96
|
+
|
|
97
|
+
## Requirements
|
|
98
|
+
|
|
99
|
+
- Node.js 18+
|
|
100
|
+
- The CLI for your chosen agent type ([Claude Code](https://docs.anthropic.com/en/docs/claude-code) or [Codex](https://github.com/openai/codex))
|
|
101
|
+
|
|
102
|
+
## Learn More
|
|
103
|
+
|
|
104
|
+
Visit [cortices.io](https://cortices.io) to get started.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { dirname, resolve } from 'path'
|
|
4
|
+
import { fileURLToPath } from 'url'
|
|
5
|
+
import { existsSync } from 'fs'
|
|
6
|
+
import { execFileSync } from 'child_process'
|
|
7
|
+
|
|
8
|
+
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
9
|
+
const bytecode = resolve(__dirname, '..', 'dist', 'claude-daemon.cjs') // bytecode loader
|
|
10
|
+
const bundled = resolve(__dirname, '..', 'dist', 'claude-daemon.mjs') // esbuild ESM
|
|
11
|
+
const source = resolve(__dirname, '..', 'claude-daemon.ts') // dev source
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
if (existsSync(bytecode)) {
|
|
15
|
+
execFileSync('node', [bytecode, ...process.argv.slice(2)], {
|
|
16
|
+
stdio: 'inherit', env: process.env,
|
|
17
|
+
})
|
|
18
|
+
} else if (existsSync(bundled)) {
|
|
19
|
+
execFileSync('node', [bundled, ...process.argv.slice(2)], {
|
|
20
|
+
stdio: 'inherit', env: process.env,
|
|
21
|
+
})
|
|
22
|
+
} else {
|
|
23
|
+
execFileSync('npx', ['tsx', source, ...process.argv.slice(2)], {
|
|
24
|
+
stdio: 'inherit', env: process.env,
|
|
25
|
+
})
|
|
26
|
+
}
|
|
27
|
+
} catch (e) {
|
|
28
|
+
process.exit(e.status || 1)
|
|
29
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { dirname, resolve } from 'path'
|
|
4
|
+
import { fileURLToPath } from 'url'
|
|
5
|
+
import { existsSync } from 'fs'
|
|
6
|
+
import { execFileSync } from 'child_process'
|
|
7
|
+
|
|
8
|
+
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
9
|
+
const bytecode = resolve(__dirname, '..', 'dist', 'codex-daemon.cjs') // bytecode loader
|
|
10
|
+
const bundled = resolve(__dirname, '..', 'dist', 'codex-daemon.mjs') // esbuild ESM
|
|
11
|
+
const source = resolve(__dirname, '..', 'codex-daemon.ts') // dev source
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
if (existsSync(bytecode)) {
|
|
15
|
+
execFileSync('node', [bytecode, ...process.argv.slice(2)], {
|
|
16
|
+
stdio: 'inherit', env: process.env,
|
|
17
|
+
})
|
|
18
|
+
} else if (existsSync(bundled)) {
|
|
19
|
+
execFileSync('node', [bundled, ...process.argv.slice(2)], {
|
|
20
|
+
stdio: 'inherit', env: process.env,
|
|
21
|
+
})
|
|
22
|
+
} else {
|
|
23
|
+
execFileSync('npx', ['tsx', source, ...process.argv.slice(2)], {
|
|
24
|
+
stdio: 'inherit', env: process.env,
|
|
25
|
+
})
|
|
26
|
+
}
|
|
27
|
+
} catch (e) {
|
|
28
|
+
process.exit(e.status || 1)
|
|
29
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { dirname, resolve } from 'path'
|
|
4
|
+
import { fileURLToPath } from 'url'
|
|
5
|
+
import { existsSync } from 'fs'
|
|
6
|
+
import { execFileSync } from 'child_process'
|
|
7
|
+
|
|
8
|
+
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
9
|
+
const bytecode = resolve(__dirname, '..', 'dist', 'cortices-daemon.cjs')
|
|
10
|
+
const bundled = resolve(__dirname, '..', 'dist', 'cortices-daemon.mjs')
|
|
11
|
+
const source = resolve(__dirname, '..', 'cortices-daemon.ts')
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
if (existsSync(bytecode)) {
|
|
15
|
+
execFileSync('node', [bytecode, ...process.argv.slice(2)], {
|
|
16
|
+
stdio: 'inherit', env: process.env,
|
|
17
|
+
})
|
|
18
|
+
} else if (existsSync(bundled)) {
|
|
19
|
+
execFileSync('node', [bundled, ...process.argv.slice(2)], {
|
|
20
|
+
stdio: 'inherit', env: process.env,
|
|
21
|
+
})
|
|
22
|
+
} else {
|
|
23
|
+
execFileSync('npx', ['tsx', source, ...process.argv.slice(2)], {
|
|
24
|
+
stdio: 'inherit', env: process.env,
|
|
25
|
+
})
|
|
26
|
+
}
|
|
27
|
+
} catch (e) {
|
|
28
|
+
process.exit(e.status || 1)
|
|
29
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { dirname, resolve } from 'path'
|
|
4
|
+
import { fileURLToPath } from 'url'
|
|
5
|
+
import { existsSync } from 'fs'
|
|
6
|
+
import { execFileSync } from 'child_process'
|
|
7
|
+
|
|
8
|
+
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
9
|
+
const bytecode = resolve(__dirname, '..', 'dist', 'opencode-daemon.cjs') // bytecode loader
|
|
10
|
+
const bundled = resolve(__dirname, '..', 'dist', 'opencode-daemon.mjs') // esbuild ESM
|
|
11
|
+
const source = resolve(__dirname, '..', 'opencode-daemon.ts') // dev source
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
if (existsSync(bytecode)) {
|
|
15
|
+
execFileSync('node', [bytecode, ...process.argv.slice(2)], {
|
|
16
|
+
stdio: 'inherit', env: process.env,
|
|
17
|
+
})
|
|
18
|
+
} else if (existsSync(bundled)) {
|
|
19
|
+
execFileSync('node', [bundled, ...process.argv.slice(2)], {
|
|
20
|
+
stdio: 'inherit', env: process.env,
|
|
21
|
+
})
|
|
22
|
+
} else {
|
|
23
|
+
execFileSync('npx', ['tsx', source, ...process.argv.slice(2)], {
|
|
24
|
+
stdio: 'inherit', env: process.env,
|
|
25
|
+
})
|
|
26
|
+
}
|
|
27
|
+
} catch (e) {
|
|
28
|
+
process.exit(e.status || 1)
|
|
29
|
+
}
|
package/bin/cortices.mjs
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { dirname, resolve } from 'path'
|
|
4
|
+
import { fileURLToPath } from 'url'
|
|
5
|
+
import { existsSync } from 'fs'
|
|
6
|
+
import { execFileSync } from 'child_process'
|
|
7
|
+
|
|
8
|
+
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
9
|
+
|
|
10
|
+
const args = process.argv.slice(2)
|
|
11
|
+
const SERVICE_COMMANDS = ['install', 'uninstall', 'restart', 'list', 'status']
|
|
12
|
+
const TOOL_COMMANDS = ['schedule', 'plan', 'memory', 'notify']
|
|
13
|
+
|
|
14
|
+
// Show top-level help
|
|
15
|
+
if (args.length === 0 || args[0] === '-h' || args[0] === '--help') {
|
|
16
|
+
console.log(`cortices — AI agent dashboard CLI
|
|
17
|
+
|
|
18
|
+
Usage:
|
|
19
|
+
cortices <command> [options]
|
|
20
|
+
cortices [options] Run agent in foreground (default: claude)
|
|
21
|
+
|
|
22
|
+
Service commands:
|
|
23
|
+
install Install agent as a background service
|
|
24
|
+
uninstall Remove agent service
|
|
25
|
+
restart Restart agent service(s)
|
|
26
|
+
upgrade Check for updates and upgrade all agents
|
|
27
|
+
list List installed agent services
|
|
28
|
+
status Show agent service status
|
|
29
|
+
|
|
30
|
+
Agent tools:
|
|
31
|
+
schedule Manage scheduled tasks
|
|
32
|
+
plan Manage long-running plans
|
|
33
|
+
memory Manage user memories
|
|
34
|
+
notify Send notifications to dashboard
|
|
35
|
+
|
|
36
|
+
Run options:
|
|
37
|
+
--agent TYPE Agent backend: claude (default), codex, opencode, native
|
|
38
|
+
--dir DIR Working directory (default: current directory)
|
|
39
|
+
--name NAME Agent name shown in dashboard
|
|
40
|
+
--api-key KEY Cortices API key for authentication
|
|
41
|
+
--interactive Start with interactive permission mode
|
|
42
|
+
|
|
43
|
+
Examples:
|
|
44
|
+
cortices install --api-key ck_xxx --dir /path/to/project --name my-agent
|
|
45
|
+
cortices restart my-agent
|
|
46
|
+
cortices list
|
|
47
|
+
cortices schedule list
|
|
48
|
+
cortices notify send --title "Build failed" --severity warning
|
|
49
|
+
cortices --api-key ck_xxx --dir /path/to/project # run in foreground`)
|
|
50
|
+
process.exit(0)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// ── Agent tool subcommands ──────────────────────────────────────────────────
|
|
54
|
+
if (args[0] && TOOL_COMMANDS.includes(args[0])) {
|
|
55
|
+
const tool = args[0]
|
|
56
|
+
const toolArgs = args.slice(1)
|
|
57
|
+
|
|
58
|
+
// Resolve script: prefer compiled dist, fall back to source
|
|
59
|
+
const scriptMjs = resolve(__dirname, '..', 'dist', 'scripts', `${tool}.mjs`)
|
|
60
|
+
const scriptTs = resolve(__dirname, '..', 'scripts', `${tool}.ts`)
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
if (existsSync(scriptMjs)) {
|
|
64
|
+
execFileSync('node', [scriptMjs, ...toolArgs], {
|
|
65
|
+
stdio: 'inherit', env: process.env,
|
|
66
|
+
})
|
|
67
|
+
} else if (existsSync(scriptTs)) {
|
|
68
|
+
execFileSync('npx', ['tsx', scriptTs, ...toolArgs], {
|
|
69
|
+
stdio: 'inherit', env: process.env,
|
|
70
|
+
})
|
|
71
|
+
} else {
|
|
72
|
+
console.error(`Script not found for '${tool}'. Run 'npm run build' in the agent directory.`)
|
|
73
|
+
process.exit(1)
|
|
74
|
+
}
|
|
75
|
+
} catch (e) {
|
|
76
|
+
process.exit(e.status || 1)
|
|
77
|
+
}
|
|
78
|
+
process.exit(0)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Determine agent type from --agent flag (default: claude)
|
|
82
|
+
let agentType = 'claude'
|
|
83
|
+
const agentIdx = args.indexOf('--agent')
|
|
84
|
+
if (agentIdx !== -1 && args[agentIdx + 1]) {
|
|
85
|
+
agentType = args[agentIdx + 1].toLowerCase()
|
|
86
|
+
args.splice(agentIdx, 2) // remove --agent and its value from args
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const VALID_TYPES = ['claude', 'codex', 'opencode', 'native']
|
|
90
|
+
if (!VALID_TYPES.includes(agentType)) {
|
|
91
|
+
console.error(`Unknown agent type: ${agentType}. Use: ${VALID_TYPES.join(', ')}`)
|
|
92
|
+
process.exit(1)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// 'native' type uses cortices-daemon.ts, others use <type>-daemon.ts
|
|
96
|
+
const daemonName = agentType === 'native' ? 'cortices-daemon' : `${agentType}-daemon`
|
|
97
|
+
const bytecode = resolve(__dirname, '..', 'dist', `${daemonName}.cjs`)
|
|
98
|
+
const bundled = resolve(__dirname, '..', 'dist', `${daemonName}.mjs`)
|
|
99
|
+
const source = resolve(__dirname, '..', `${daemonName}.ts`)
|
|
100
|
+
|
|
101
|
+
try {
|
|
102
|
+
if (existsSync(bytecode)) {
|
|
103
|
+
execFileSync('node', [bytecode, ...args], {
|
|
104
|
+
stdio: 'inherit', env: process.env,
|
|
105
|
+
})
|
|
106
|
+
} else if (existsSync(bundled)) {
|
|
107
|
+
execFileSync('node', [bundled, ...args], {
|
|
108
|
+
stdio: 'inherit', env: process.env,
|
|
109
|
+
})
|
|
110
|
+
} else {
|
|
111
|
+
execFileSync('npx', ['tsx', source, ...args], {
|
|
112
|
+
stdio: 'inherit', env: process.env,
|
|
113
|
+
})
|
|
114
|
+
}
|
|
115
|
+
} catch (e) {
|
|
116
|
+
process.exit(e.status || 1)
|
|
117
|
+
}
|