@arcforge/axon 0.7.2

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/LICENSE ADDED
@@ -0,0 +1,26 @@
1
+ Copyright (c) 2025 ArcForge
2
+
3
+ All rights reserved.
4
+
5
+ This software and associated documentation files (the "Software") are proprietary
6
+ and confidential to ArcForge.
7
+
8
+ The Software is licensed, not sold. This license grants you the following rights:
9
+
10
+ 1. You may install and use the Software solely for your internal business purposes.
11
+
12
+ 2. You may not:
13
+ - Modify, adapt, translate, or create derivative works of the Software
14
+ - Reverse engineer, decompile, or disassemble the Software
15
+ - Remove or alter any proprietary notices or labels on the Software
16
+ - Distribute, sublicense, lease, rent, loan, or transfer the Software to any third party
17
+ - Use the Software for any purpose other than as expressly permitted herein
18
+
19
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22
+ ARCFORGE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
23
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
+
26
+ For licensing inquiries, please contact: legal@arcforge.io
package/README.md ADDED
@@ -0,0 +1,52 @@
1
+ # Axon
2
+
3
+ > High-performance CLI coding agent with Blessed terminal UI
4
+
5
+ Axon is a powerful terminal-based coding agent that combines LLM capabilities with a beautiful text-based user interface.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install -g @arcforge/axon
11
+ ```
12
+
13
+ **Requirements:**
14
+ - [Bun](https://bun.sh) runtime installed
15
+
16
+ ## Quick Start
17
+
18
+ ```bash
19
+ axon
20
+ ```
21
+
22
+ This launches the interactive terminal UI where you can:
23
+ - Chat with the AI coding agent
24
+ - Manage multiple processes
25
+ - View and manage tasks in a Kanban board
26
+ - Customize themes and audio visualizations
27
+
28
+ ## Features
29
+
30
+ - **🎨 Beautiful Terminal UI** - Built with Blessed for a responsive TUI experience
31
+ - **🤖 AI-Powered** - Integrated LLM agent for coding assistance
32
+ - **📋 Process Management** - Monitor and control running processes
33
+ - **🎯 Task Management** - Built-in Kanban board for organizing work
34
+ - **🎵 Audio Visualizer** - Real-time audio visualization in your terminal
35
+ - **🔐 Device Authentication** - Secure authentication flow
36
+ - **⚡ High Performance** - Built with Bun for speed
37
+
38
+ ## Usage
39
+
40
+ Once launched, use keyboard shortcuts to navigate:
41
+ - Arrow keys to navigate menus
42
+ - Enter to select
43
+ - Esc to go back
44
+ - Tab to switch between panels
45
+
46
+ Visit the in-app profile page for more keyboard shortcuts and settings.
47
+
48
+ ## License
49
+
50
+ Copyright © 2025 ArcForge. All rights reserved.
51
+
52
+ This is proprietary software. Unauthorized copying, modification, distribution, or use of this software is strictly prohibited.
package/app/index.ts ADDED
@@ -0,0 +1,204 @@
1
+ import blessed from "blessed"
2
+
3
+ import {
4
+ useAudioVisualizer,
5
+ useScreen,
6
+ useCommands,
7
+ useCognos,
8
+ useStack,
9
+ useRouter,
10
+ useDeviceAuth,
11
+ } from "#composables"
12
+
13
+ import {
14
+ ChatPage,
15
+ KanbanPage,
16
+ LoginPage,
17
+ ProcessesPage,
18
+ ProcessDetailPage,
19
+ ProfilePage,
20
+ ThemePage,
21
+ } from "#pages"
22
+ import { builtinCommands, processCommands, kanbanCommands, parseArgs, printHelp, executePrompt, redirectConsoleToFile, restoreConsole, getLogFilePath } from "#lib"
23
+ import { Footer } from "#components"
24
+
25
+
26
+ /**
27
+ * Interactive mode: Full blessed TUI
28
+ *
29
+ * The screen consists of two regions:
30
+ *
31
+ * - The current page (chat, login, etc.), containing page-specific content.
32
+ * - The footer, containing chat input and menus.
33
+ *
34
+ */
35
+ async function mainInteractive(debug: boolean = false) {
36
+ // Redirect console output to prevent TUI corruption (unless debug mode)
37
+ if (!debug) {
38
+ redirectConsoleToFile()
39
+ }
40
+
41
+ const screen = useScreen()
42
+ const commands = useCommands()
43
+ const stackComposable = useStack()
44
+ const cognos = useCognos()
45
+ const router = useRouter()
46
+ const deviceAuth = useDeviceAuth()
47
+
48
+ // Register builtin commands
49
+ builtinCommands.forEach(cmd => commands.register(cmd))
50
+
51
+ // Register process management commands
52
+ processCommands.forEach(cmd => commands.register(cmd))
53
+
54
+ // Register kanban commands
55
+ kanbanCommands.forEach(cmd => commands.register(cmd))
56
+
57
+
58
+ // Navigate to chat immediately if at root
59
+ if (router.current().path === "/") {
60
+ router.navigate("/chat")
61
+ }
62
+
63
+ // Start auth check in background (non-blocking)
64
+ // The result will be awaited later when the user sends their first message
65
+ deviceAuth.checkAuth().then(isAuthenticated => {
66
+ if (isAuthenticated) {
67
+ // Only connect to websocket after successful auth
68
+ cognos.connect().catch(error => {
69
+ console.error("Failed to connect to websocket:", error)
70
+ })
71
+ } else if (router.current().path !== "/login") {
72
+ // Redirect to login if auth fails
73
+ router.navigate("/login")
74
+ }
75
+ })
76
+
77
+ const container = blessed.box({
78
+ width: "100%",
79
+ height: "100%",
80
+ layout: "vertical",
81
+ })
82
+
83
+ const footer = Footer()
84
+
85
+ // Create page mapping with route patterns
86
+ const routes = [
87
+ { pattern: "/login", component: () => LoginPage() },
88
+ { pattern: "/chat", component: () => ChatPage() },
89
+ { pattern: "/kanban", component: () => KanbanPage() },
90
+ { pattern: "/processes", component: () => ProcessesPage() },
91
+ { pattern: "/processes/:refId", component: () => ProcessDetailPage() },
92
+ { pattern: "/profile", component: () => ProfilePage() },
93
+ { pattern: "/theme", component: () => ThemePage() },
94
+ ]
95
+
96
+ // Helper to find matching route
97
+ function findMatchingRoute(path: string) {
98
+ for (const route of routes) {
99
+ const match = router.match(route.pattern)
100
+ if (match) {
101
+ return route
102
+ }
103
+ }
104
+ // Default to login if no match
105
+ return routes[0]
106
+ }
107
+
108
+ // Initialize with the current page
109
+ const initialRoute = findMatchingRoute(router.current().path)
110
+ let currentPageNode = initialRoute.component().node
111
+
112
+ container.append(footer.node)
113
+ container.append(currentPageNode)
114
+
115
+ screen.append(container)
116
+ screen.append(footer.paletteNode) // Append command palette to screen so it floats above footer
117
+ screen.append(footer.pagePaletteNode) // Append page palette to screen so it floats above footer
118
+ screen.render()
119
+
120
+ // Focus the input initially
121
+ footer.focus()
122
+
123
+ // Handle page navigation
124
+ router.onNavigate((route) => {
125
+ // Remove current page
126
+ container.remove(currentPageNode)
127
+
128
+ // Find matching route and create page
129
+ const matchedRoute = findMatchingRoute(route.path)
130
+ currentPageNode = matchedRoute.component().node
131
+ container.append(currentPageNode)
132
+
133
+ // Keep footer on top
134
+ container.remove(footer.node)
135
+ container.append(footer.node)
136
+
137
+ screen.render()
138
+ })
139
+
140
+ // Initialize audio visualizer (will activate in voice mode)
141
+ const audioVisualizer = useAudioVisualizer()
142
+ audioVisualizer.init()
143
+
144
+ // Show Axon logo and stats on boot
145
+ const axonCmd = builtinCommands.find(cmd => cmd.name === "axon")
146
+ if (axonCmd) {
147
+ axonCmd.execute()
148
+ }
149
+
150
+ stackComposable.onUpdate(() => {
151
+ // Put the footer back at the top (z-index).
152
+ container.remove(footer.node)
153
+ container.append(footer.node)
154
+ screen.render()
155
+ })
156
+
157
+ // Setup cleanup handlers for websocket and capsule
158
+ const cleanup = async () => {
159
+ cognos.disconnect()
160
+ if (!debug) {
161
+ restoreConsole()
162
+ }
163
+ }
164
+
165
+ process.on("SIGINT", async () => {
166
+ await cleanup()
167
+ process.exit(0)
168
+ })
169
+
170
+ process.on("exit", async () => {
171
+ await cleanup()
172
+ })
173
+
174
+ screen.key(["C-c"], async () => {
175
+ await cleanup()
176
+ process.exit(0)
177
+ })
178
+ }
179
+
180
+ /**
181
+ * Main entry point: Parse args and route to appropriate mode
182
+ */
183
+ async function main() {
184
+ const args = parseArgs(process.argv.slice(2))
185
+
186
+ if (args.help) {
187
+ printHelp()
188
+ process.exit(0)
189
+ }
190
+
191
+ if (args.mode === 'prompt') {
192
+ if (!args.prompt) {
193
+ console.error("Error: --prompt requires a value")
194
+ process.exit(1)
195
+ }
196
+ await executePrompt(args.prompt)
197
+ process.exit(0)
198
+ }
199
+
200
+ // Interactive mode (default)
201
+ await mainInteractive(args.debug || false)
202
+ }
203
+
204
+ await main()