ikanban-web 0.2.5 → 0.2.7
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 +25 -20
- package/bin/cli.js +37 -5
- package/dist/assets/{ghostty-web-Cg-QA7iC.js → ghostty-web-BnnMBzi5.js} +1 -1
- package/dist/assets/{home-CugMWlKZ.js → home-DeLBKxk3.js} +1 -1
- package/dist/assets/{index-DN6xwyZa.js → index-ehO8js0v.js} +36 -36
- package/dist/assets/index-pnX-hTQP.css +1 -0
- package/dist/assets/session-D7vMISoz.js +24 -0
- package/dist/index.html +9 -9
- package/package.json +1 -1
- package/src/app.tsx +1 -0
- package/src/components/session/session-header.tsx +2 -211
- package/src/context/server.tsx +24 -4
- package/src/entry.tsx +5 -1
- package/src/i18n/en.ts +1 -1
- package/src/i18n/parity.test.ts +4 -22
- package/src/i18n/zh.ts +1 -1
- package/src/pages/layout.tsx +2 -2
- package/src/pages/session/use-session-commands.tsx +0 -121
- package/dist/assets/index-CitLv2ln.css +0 -1
- package/dist/assets/session-D1ZywRf4.js +0 -24
- package/src/i18n/ar.ts +0 -751
- package/src/i18n/br.ts +0 -759
- package/src/i18n/bs.ts +0 -836
- package/src/i18n/da.ts +0 -830
- package/src/i18n/de.ts +0 -768
- package/src/i18n/es.ts +0 -842
- package/src/i18n/fr.ts +0 -766
- package/src/i18n/ja.ts +0 -755
- package/src/i18n/ko.ts +0 -755
- package/src/i18n/no.ts +0 -838
- package/src/i18n/pl.ts +0 -757
- package/src/i18n/ru.ts +0 -838
- package/src/i18n/th.ts +0 -828
- package/src/i18n/tr.ts +0 -849
- package/src/i18n/zht.ts +0 -821
package/README.md
CHANGED
|
@@ -1,34 +1,39 @@
|
|
|
1
|
-
|
|
1
|
+
# ikanban
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
iKanban is a Web interface for the [OpenCode](https://opencode.ai) AI coding agent. It unifies chat, terminal, and board workflows in a single interface so teams can plan, execute, and track coding tasks.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## UI Previews
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
```
|
|
7
|
+
<details>
|
|
8
|
+
<summary>Expand screenshots</summary>
|
|
10
9
|
|
|
11
|
-
|
|
10
|
+
<img width="3695" height="2149" alt="Image" src="https://github.com/user-attachments/assets/b5ca21b8-b8aa-46f6-84cc-8906f629b6c8" />
|
|
12
11
|
|
|
13
|
-
|
|
12
|
+
</details>
|
|
14
13
|
|
|
15
|
-
|
|
14
|
+
## Quick Start
|
|
16
15
|
|
|
17
|
-
###
|
|
16
|
+
### Option 1: Use the hosted app (recommended)
|
|
18
17
|
|
|
19
|
-
|
|
20
|
-
Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
|
|
18
|
+
Open: https://isomoes.github.io/ikanban
|
|
21
19
|
|
|
22
|
-
|
|
20
|
+
Start OpenCode with CORS enabled for GitHub Pages:
|
|
23
21
|
|
|
24
|
-
|
|
22
|
+
```bash
|
|
23
|
+
opencode serve --port <PORT> --cors https://isomoes.github.io
|
|
24
|
+
```
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
It correctly bundles Solid in production mode and optimizes the build for the best performance.
|
|
26
|
+
Then add your server URL in settings: `http://localhost:<PORT>`.
|
|
28
27
|
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
### Option 2: Run locally with npx
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npx ikanban-web@latest # Start on port 3000
|
|
32
|
+
npx ikanban-web@latest --port 8080 # Custom port
|
|
33
|
+
OPENCODE_URL=http://myserver:4096 npx ikanban-web@latest # External OpenCode server
|
|
34
|
+
```
|
|
31
35
|
|
|
32
|
-
##
|
|
36
|
+
## Acknowledgments
|
|
33
37
|
|
|
34
|
-
|
|
38
|
+
- Inspired by and thanks to the [openchamber](https://github.com/btriapitsyn/openchamber) project.
|
|
39
|
+
- [opencode web UI](https://github.com/anomalyco/opencode/tree/dev/packages/app)
|
package/bin/cli.js
CHANGED
|
@@ -30,8 +30,9 @@ const PORT = portFlag !== -1 ? parseInt(args[portFlag + 1], 10) : 3000
|
|
|
30
30
|
// OpenCode backend: honour OPENCODE_URL or default to localhost:4096
|
|
31
31
|
const OPENCODE_URL = process.env.OPENCODE_URL || "http://localhost:4096"
|
|
32
32
|
|
|
33
|
-
function proxyRequest(req, res) {
|
|
33
|
+
function proxyRequest(req, res, overridePath) {
|
|
34
34
|
const target = new URL(req.url, OPENCODE_URL)
|
|
35
|
+
if (overridePath !== undefined) target.pathname = overridePath
|
|
35
36
|
const mod = target.protocol === "https:" ? https : http
|
|
36
37
|
const options = {
|
|
37
38
|
hostname: target.hostname,
|
|
@@ -51,9 +52,18 @@ function proxyRequest(req, res) {
|
|
|
51
52
|
req.pipe(proxy)
|
|
52
53
|
}
|
|
53
54
|
|
|
55
|
+
const BASE = "/ikanban"
|
|
56
|
+
|
|
54
57
|
const server = http.createServer((req, res) => {
|
|
55
58
|
const url = new URL(req.url, `http://localhost:${PORT}`)
|
|
56
59
|
|
|
60
|
+
// Redirect bare /ikanban to /ikanban/
|
|
61
|
+
if (url.pathname === BASE) {
|
|
62
|
+
res.writeHead(301, { Location: BASE + "/" })
|
|
63
|
+
res.end()
|
|
64
|
+
return
|
|
65
|
+
}
|
|
66
|
+
|
|
57
67
|
// Proxy OpenCode API paths to backend.
|
|
58
68
|
// These are the top-level path segments used by @opencode-ai/sdk.
|
|
59
69
|
const API_PREFIXES = [
|
|
@@ -82,15 +92,37 @@ const server = http.createServer((req, res) => {
|
|
|
82
92
|
"/tui",
|
|
83
93
|
"/vcs",
|
|
84
94
|
]
|
|
95
|
+
// Support both /session/... (SDK default, same-origin) and
|
|
96
|
+
// /ikanban/session/... (prefixed, e.g. from a reverse proxy).
|
|
97
|
+
// Determine the effective API pathname by stripping the base prefix if present.
|
|
98
|
+
let apiPathname = url.pathname
|
|
99
|
+
if (apiPathname.startsWith(BASE + "/")) {
|
|
100
|
+
const stripped = apiPathname.slice(BASE.length)
|
|
101
|
+
if (API_PREFIXES.some((p) => stripped === p || stripped.startsWith(p + "/"))) {
|
|
102
|
+
apiPathname = stripped
|
|
103
|
+
}
|
|
104
|
+
}
|
|
85
105
|
const isApi = API_PREFIXES.some(
|
|
86
|
-
(p) =>
|
|
106
|
+
(p) => apiPathname === p || apiPathname.startsWith(p + "/"),
|
|
87
107
|
)
|
|
88
108
|
if (isApi) {
|
|
89
|
-
|
|
109
|
+
// Pass the stripped path so the backend never sees the /ikanban prefix
|
|
110
|
+
return proxyRequest(req, res, apiPathname !== url.pathname ? apiPathname : undefined)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Strip /ikanban prefix before resolving static files
|
|
114
|
+
let pathname = url.pathname
|
|
115
|
+
if (pathname.startsWith(BASE + "/")) {
|
|
116
|
+
pathname = pathname.slice(BASE.length) || "/"
|
|
117
|
+
} else if (pathname !== BASE) {
|
|
118
|
+
// Anything outside /ikanban/ that isn't an API call gets a 404
|
|
119
|
+
res.writeHead(404)
|
|
120
|
+
res.end("Not found")
|
|
121
|
+
return
|
|
90
122
|
}
|
|
91
123
|
|
|
92
124
|
// Serve static files from dist/
|
|
93
|
-
let filePath = path.join(DIST,
|
|
125
|
+
let filePath = path.join(DIST, pathname)
|
|
94
126
|
if (!fs.existsSync(filePath) || fs.statSync(filePath).isDirectory()) {
|
|
95
127
|
filePath = path.join(DIST, "index.html")
|
|
96
128
|
}
|
|
@@ -110,7 +142,7 @@ const server = http.createServer((req, res) => {
|
|
|
110
142
|
})
|
|
111
143
|
|
|
112
144
|
server.listen(PORT, () => {
|
|
113
|
-
console.log(`iKanban running at http://localhost:${PORT}
|
|
145
|
+
console.log(`iKanban running at http://localhost:${PORT}${BASE}/`)
|
|
114
146
|
console.log(`OpenCode backend: ${OPENCODE_URL}`)
|
|
115
147
|
console.log("Press Ctrl+C to stop")
|
|
116
148
|
})
|