@cluesmith/codev 2.0.0-rc.4 → 2.0.0-rc.40
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/porch.js +6 -35
- package/dashboard/dist/assets/index-BLqoFC1H.js +120 -0
- package/dashboard/dist/assets/index-BLqoFC1H.js.map +1 -0
- package/dashboard/dist/assets/index-CXwnJkPh.css +32 -0
- package/dashboard/dist/index.html +13 -0
- package/dist/agent-farm/cli.d.ts.map +1 -1
- package/dist/agent-farm/cli.js +93 -64
- package/dist/agent-farm/cli.js.map +1 -1
- package/dist/agent-farm/commands/architect.d.ts.map +1 -1
- package/dist/agent-farm/commands/architect.js +13 -6
- package/dist/agent-farm/commands/architect.js.map +1 -1
- package/dist/agent-farm/commands/attach.d.ts +13 -0
- package/dist/agent-farm/commands/attach.d.ts.map +1 -0
- package/dist/agent-farm/commands/attach.js +179 -0
- package/dist/agent-farm/commands/attach.js.map +1 -0
- package/dist/agent-farm/commands/cleanup.d.ts.map +1 -1
- package/dist/agent-farm/commands/cleanup.js +30 -3
- package/dist/agent-farm/commands/cleanup.js.map +1 -1
- package/dist/agent-farm/commands/consult.js +1 -1
- package/dist/agent-farm/commands/consult.js.map +1 -1
- package/dist/agent-farm/commands/index.d.ts +2 -2
- package/dist/agent-farm/commands/index.d.ts.map +1 -1
- package/dist/agent-farm/commands/index.js +2 -2
- package/dist/agent-farm/commands/index.js.map +1 -1
- package/dist/agent-farm/commands/{util.d.ts → shell.d.ts} +5 -5
- package/dist/agent-farm/commands/shell.d.ts.map +1 -0
- package/dist/agent-farm/commands/{util.js → shell.js} +23 -36
- package/dist/agent-farm/commands/shell.js.map +1 -0
- package/dist/agent-farm/commands/spawn.d.ts.map +1 -1
- package/dist/agent-farm/commands/spawn.js +455 -217
- package/dist/agent-farm/commands/spawn.js.map +1 -1
- package/dist/agent-farm/commands/start.d.ts.map +1 -1
- package/dist/agent-farm/commands/start.js +27 -79
- package/dist/agent-farm/commands/start.js.map +1 -1
- package/dist/agent-farm/commands/stop.d.ts.map +1 -1
- package/dist/agent-farm/commands/stop.js +79 -10
- package/dist/agent-farm/commands/stop.js.map +1 -1
- package/dist/agent-farm/commands/tower.d.ts +9 -0
- package/dist/agent-farm/commands/tower.d.ts.map +1 -1
- package/dist/agent-farm/commands/tower.js +54 -18
- package/dist/agent-farm/commands/tower.js.map +1 -1
- package/dist/agent-farm/db/index.d.ts.map +1 -1
- package/dist/agent-farm/db/index.js +15 -0
- package/dist/agent-farm/db/index.js.map +1 -1
- package/dist/agent-farm/db/schema.d.ts +1 -1
- package/dist/agent-farm/db/schema.d.ts.map +1 -1
- package/dist/agent-farm/db/schema.js +6 -3
- package/dist/agent-farm/db/schema.js.map +1 -1
- package/dist/agent-farm/db/types.d.ts +3 -0
- package/dist/agent-farm/db/types.d.ts.map +1 -1
- package/dist/agent-farm/db/types.js +3 -0
- package/dist/agent-farm/db/types.js.map +1 -1
- package/dist/agent-farm/hq-connector.d.ts +2 -2
- package/dist/agent-farm/hq-connector.js +2 -2
- package/dist/agent-farm/servers/dashboard-server.js +435 -131
- package/dist/agent-farm/servers/dashboard-server.js.map +1 -1
- package/dist/agent-farm/servers/tower-server.js +430 -17
- package/dist/agent-farm/servers/tower-server.js.map +1 -1
- package/dist/agent-farm/state.d.ts +4 -10
- package/dist/agent-farm/state.d.ts.map +1 -1
- package/dist/agent-farm/state.js +30 -31
- package/dist/agent-farm/state.js.map +1 -1
- package/dist/agent-farm/types.d.ts +48 -0
- package/dist/agent-farm/types.d.ts.map +1 -1
- package/dist/agent-farm/utils/config.d.ts.map +1 -1
- package/dist/agent-farm/utils/config.js +12 -11
- package/dist/agent-farm/utils/config.js.map +1 -1
- package/dist/agent-farm/utils/deps.d.ts.map +1 -1
- package/dist/agent-farm/utils/deps.js +0 -16
- package/dist/agent-farm/utils/deps.js.map +1 -1
- package/dist/agent-farm/utils/notifications.d.ts +30 -0
- package/dist/agent-farm/utils/notifications.d.ts.map +1 -0
- package/dist/agent-farm/utils/notifications.js +121 -0
- package/dist/agent-farm/utils/notifications.js.map +1 -0
- package/dist/agent-farm/utils/server-utils.d.ts +2 -1
- package/dist/agent-farm/utils/server-utils.d.ts.map +1 -1
- package/dist/agent-farm/utils/server-utils.js +11 -1
- package/dist/agent-farm/utils/server-utils.js.map +1 -1
- package/dist/agent-farm/utils/shell.d.ts +9 -22
- package/dist/agent-farm/utils/shell.d.ts.map +1 -1
- package/dist/agent-farm/utils/shell.js +34 -34
- package/dist/agent-farm/utils/shell.js.map +1 -1
- package/dist/agent-farm/utils/terminal-ports.d.ts +1 -1
- package/dist/agent-farm/utils/terminal-ports.js +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +5 -54
- package/dist/cli.js.map +1 -1
- package/dist/commands/adopt.d.ts.map +1 -1
- package/dist/commands/adopt.js +39 -4
- package/dist/commands/adopt.js.map +1 -1
- package/dist/commands/consult/index.d.ts.map +1 -1
- package/dist/commands/consult/index.js +63 -3
- package/dist/commands/consult/index.js.map +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +0 -15
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +31 -2
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/porch/build-counter.d.ts +5 -0
- package/dist/commands/porch/build-counter.d.ts.map +1 -0
- package/dist/commands/porch/build-counter.js +5 -0
- package/dist/commands/porch/build-counter.js.map +1 -0
- package/dist/commands/porch/checks.d.ts +16 -29
- package/dist/commands/porch/checks.d.ts.map +1 -1
- package/dist/commands/porch/checks.js +90 -144
- package/dist/commands/porch/checks.js.map +1 -1
- package/dist/commands/porch/claude.d.ts +27 -0
- package/dist/commands/porch/claude.d.ts.map +1 -0
- package/dist/commands/porch/claude.js +107 -0
- package/dist/commands/porch/claude.js.map +1 -0
- package/dist/commands/porch/index.d.ts +21 -43
- package/dist/commands/porch/index.d.ts.map +1 -1
- package/dist/commands/porch/index.js +466 -926
- package/dist/commands/porch/index.js.map +1 -1
- package/dist/commands/porch/plan.d.ts +70 -0
- package/dist/commands/porch/plan.d.ts.map +1 -0
- package/dist/commands/porch/plan.js +190 -0
- package/dist/commands/porch/plan.js.map +1 -0
- package/dist/commands/porch/prompts.d.ts +19 -0
- package/dist/commands/porch/prompts.d.ts.map +1 -0
- package/dist/commands/porch/prompts.js +250 -0
- package/dist/commands/porch/prompts.js.map +1 -0
- package/dist/commands/porch/protocol.d.ts +59 -0
- package/dist/commands/porch/protocol.d.ts.map +1 -0
- package/dist/commands/porch/protocol.js +260 -0
- package/dist/commands/porch/protocol.js.map +1 -0
- package/dist/commands/porch/run.d.ts +40 -0
- package/dist/commands/porch/run.d.ts.map +1 -0
- package/dist/commands/porch/run.js +893 -0
- package/dist/commands/porch/run.js.map +1 -0
- package/dist/commands/porch/state.d.ts +23 -112
- package/dist/commands/porch/state.d.ts.map +1 -1
- package/dist/commands/porch/state.js +81 -699
- package/dist/commands/porch/state.js.map +1 -1
- package/dist/commands/porch/types.d.ts +72 -173
- package/dist/commands/porch/types.d.ts.map +1 -1
- package/dist/commands/porch/types.js +2 -1
- package/dist/commands/porch/types.js.map +1 -1
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +22 -0
- package/dist/commands/update.js.map +1 -1
- package/dist/lib/scaffold.d.ts +24 -0
- package/dist/lib/scaffold.d.ts.map +1 -1
- package/dist/lib/scaffold.js +78 -0
- package/dist/lib/scaffold.js.map +1 -1
- package/dist/terminal/index.d.ts +8 -0
- package/dist/terminal/index.d.ts.map +1 -0
- package/dist/terminal/index.js +5 -0
- package/dist/terminal/index.js.map +1 -0
- package/dist/terminal/pty-manager.d.ts +60 -0
- package/dist/terminal/pty-manager.d.ts.map +1 -0
- package/dist/terminal/pty-manager.js +334 -0
- package/dist/terminal/pty-manager.js.map +1 -0
- package/dist/terminal/pty-session.d.ts +79 -0
- package/dist/terminal/pty-session.d.ts.map +1 -0
- package/dist/terminal/pty-session.js +215 -0
- package/dist/terminal/pty-session.js.map +1 -0
- package/dist/terminal/ring-buffer.d.ts +27 -0
- package/dist/terminal/ring-buffer.d.ts.map +1 -0
- package/dist/terminal/ring-buffer.js +74 -0
- package/dist/terminal/ring-buffer.js.map +1 -0
- package/dist/terminal/ws-protocol.d.ts +27 -0
- package/dist/terminal/ws-protocol.d.ts.map +1 -0
- package/dist/terminal/ws-protocol.js +44 -0
- package/dist/terminal/ws-protocol.js.map +1 -0
- package/package.json +18 -3
- package/skeleton/DEPENDENCIES.md +3 -29
- package/skeleton/builders.md +1 -1
- package/skeleton/protocol-schema.json +282 -0
- package/skeleton/protocols/bugfix/builder-prompt.md +49 -0
- package/skeleton/protocols/bugfix/protocol.json +14 -2
- package/skeleton/protocols/experiment/builder-prompt.md +47 -0
- package/skeleton/protocols/experiment/protocol.json +101 -0
- package/skeleton/protocols/maintain/builder-prompt.md +41 -0
- package/skeleton/protocols/maintain/prompts/audit.md +111 -0
- package/skeleton/protocols/maintain/prompts/clean.md +91 -0
- package/skeleton/protocols/maintain/prompts/sync.md +113 -0
- package/skeleton/protocols/maintain/prompts/verify.md +110 -0
- package/skeleton/protocols/maintain/protocol.json +141 -0
- package/skeleton/protocols/maintain/protocol.md +13 -7
- package/skeleton/protocols/protocol-schema.json +53 -0
- package/skeleton/protocols/spider/builder-prompt.md +53 -0
- package/skeleton/protocols/spider/prompts/implement.md +109 -50
- package/skeleton/protocols/spider/prompts/specify.md +29 -4
- package/skeleton/protocols/spider/protocol.json +96 -154
- package/skeleton/protocols/spider/protocol.md +26 -16
- package/skeleton/protocols/spider/templates/plan.md +14 -0
- package/skeleton/protocols/tick/builder-prompt.md +51 -0
- package/skeleton/protocols/tick/protocol.json +7 -2
- package/skeleton/resources/commands/agent-farm.md +25 -43
- package/skeleton/resources/commands/overview.md +6 -16
- package/skeleton/resources/workflow-reference.md +2 -2
- package/skeleton/roles/architect.md +152 -315
- package/skeleton/roles/builder.md +109 -218
- package/skeleton/templates/AGENTS.md +1 -1
- package/skeleton/templates/CLAUDE.md +1 -1
- package/skeleton/templates/cheatsheet.md +4 -2
- package/templates/dashboard/index.html +17 -43
- package/templates/dashboard/js/dialogs.js +7 -7
- package/templates/dashboard/js/files.js +2 -2
- package/templates/dashboard/js/main.js +3 -3
- package/templates/dashboard/js/projects.js +3 -3
- package/templates/dashboard/js/tabs.js +1 -1
- package/templates/dashboard/js/utils.js +22 -87
- package/templates/tower.html +497 -26
- package/dist/agent-farm/commands/kickoff.d.ts +0 -19
- package/dist/agent-farm/commands/kickoff.d.ts.map +0 -1
- package/dist/agent-farm/commands/kickoff.js +0 -331
- package/dist/agent-farm/commands/kickoff.js.map +0 -1
- package/dist/agent-farm/commands/rename.d.ts +0 -13
- package/dist/agent-farm/commands/rename.d.ts.map +0 -1
- package/dist/agent-farm/commands/rename.js +0 -33
- package/dist/agent-farm/commands/rename.js.map +0 -1
- package/dist/agent-farm/commands/tutorial.d.ts +0 -10
- package/dist/agent-farm/commands/tutorial.d.ts.map +0 -1
- package/dist/agent-farm/commands/tutorial.js +0 -49
- package/dist/agent-farm/commands/tutorial.js.map +0 -1
- package/dist/agent-farm/commands/util.d.ts.map +0 -1
- package/dist/agent-farm/commands/util.js.map +0 -1
- package/dist/agent-farm/tutorial/index.d.ts +0 -8
- package/dist/agent-farm/tutorial/index.d.ts.map +0 -1
- package/dist/agent-farm/tutorial/index.js +0 -8
- package/dist/agent-farm/tutorial/index.js.map +0 -1
- package/dist/agent-farm/tutorial/prompts.d.ts +0 -57
- package/dist/agent-farm/tutorial/prompts.d.ts.map +0 -1
- package/dist/agent-farm/tutorial/prompts.js +0 -147
- package/dist/agent-farm/tutorial/prompts.js.map +0 -1
- package/dist/agent-farm/tutorial/runner.d.ts +0 -52
- package/dist/agent-farm/tutorial/runner.d.ts.map +0 -1
- package/dist/agent-farm/tutorial/runner.js +0 -204
- package/dist/agent-farm/tutorial/runner.js.map +0 -1
- package/dist/agent-farm/tutorial/state.d.ts +0 -26
- package/dist/agent-farm/tutorial/state.d.ts.map +0 -1
- package/dist/agent-farm/tutorial/state.js +0 -89
- package/dist/agent-farm/tutorial/state.js.map +0 -1
- package/dist/agent-farm/tutorial/steps/first-spec.d.ts +0 -7
- package/dist/agent-farm/tutorial/steps/first-spec.d.ts.map +0 -1
- package/dist/agent-farm/tutorial/steps/first-spec.js +0 -136
- package/dist/agent-farm/tutorial/steps/first-spec.js.map +0 -1
- package/dist/agent-farm/tutorial/steps/implementation.d.ts +0 -7
- package/dist/agent-farm/tutorial/steps/implementation.d.ts.map +0 -1
- package/dist/agent-farm/tutorial/steps/implementation.js +0 -76
- package/dist/agent-farm/tutorial/steps/implementation.js.map +0 -1
- package/dist/agent-farm/tutorial/steps/index.d.ts +0 -10
- package/dist/agent-farm/tutorial/steps/index.d.ts.map +0 -1
- package/dist/agent-farm/tutorial/steps/index.js +0 -10
- package/dist/agent-farm/tutorial/steps/index.js.map +0 -1
- package/dist/agent-farm/tutorial/steps/planning.d.ts +0 -7
- package/dist/agent-farm/tutorial/steps/planning.d.ts.map +0 -1
- package/dist/agent-farm/tutorial/steps/planning.js +0 -143
- package/dist/agent-farm/tutorial/steps/planning.js.map +0 -1
- package/dist/agent-farm/tutorial/steps/review.d.ts +0 -7
- package/dist/agent-farm/tutorial/steps/review.d.ts.map +0 -1
- package/dist/agent-farm/tutorial/steps/review.js +0 -78
- package/dist/agent-farm/tutorial/steps/review.js.map +0 -1
- package/dist/agent-farm/tutorial/steps/setup.d.ts +0 -7
- package/dist/agent-farm/tutorial/steps/setup.d.ts.map +0 -1
- package/dist/agent-farm/tutorial/steps/setup.js +0 -126
- package/dist/agent-farm/tutorial/steps/setup.js.map +0 -1
- package/dist/agent-farm/tutorial/steps/welcome.d.ts +0 -7
- package/dist/agent-farm/tutorial/steps/welcome.d.ts.map +0 -1
- package/dist/agent-farm/tutorial/steps/welcome.js +0 -50
- package/dist/agent-farm/tutorial/steps/welcome.js.map +0 -1
- package/dist/commands/pcheck/cache.d.ts +0 -48
- package/dist/commands/pcheck/cache.d.ts.map +0 -1
- package/dist/commands/pcheck/cache.js +0 -170
- package/dist/commands/pcheck/cache.js.map +0 -1
- package/dist/commands/pcheck/evaluator.d.ts +0 -15
- package/dist/commands/pcheck/evaluator.d.ts.map +0 -1
- package/dist/commands/pcheck/evaluator.js +0 -246
- package/dist/commands/pcheck/evaluator.js.map +0 -1
- package/dist/commands/pcheck/index.d.ts +0 -12
- package/dist/commands/pcheck/index.d.ts.map +0 -1
- package/dist/commands/pcheck/index.js +0 -249
- package/dist/commands/pcheck/index.js.map +0 -1
- package/dist/commands/pcheck/parser.d.ts +0 -39
- package/dist/commands/pcheck/parser.d.ts.map +0 -1
- package/dist/commands/pcheck/parser.js +0 -155
- package/dist/commands/pcheck/parser.js.map +0 -1
- package/dist/commands/pcheck/types.d.ts +0 -82
- package/dist/commands/pcheck/types.d.ts.map +0 -1
- package/dist/commands/pcheck/types.js +0 -5
- package/dist/commands/pcheck/types.js.map +0 -1
- package/dist/commands/porch/consultation.d.ts +0 -56
- package/dist/commands/porch/consultation.d.ts.map +0 -1
- package/dist/commands/porch/consultation.js +0 -330
- package/dist/commands/porch/consultation.js.map +0 -1
- package/dist/commands/porch/notifications.d.ts +0 -99
- package/dist/commands/porch/notifications.d.ts.map +0 -1
- package/dist/commands/porch/notifications.js +0 -223
- package/dist/commands/porch/notifications.js.map +0 -1
- package/dist/commands/porch/plan-parser.d.ts +0 -38
- package/dist/commands/porch/plan-parser.d.ts.map +0 -1
- package/dist/commands/porch/plan-parser.js +0 -166
- package/dist/commands/porch/plan-parser.js.map +0 -1
- package/dist/commands/porch/protocol-loader.d.ts +0 -46
- package/dist/commands/porch/protocol-loader.d.ts.map +0 -1
- package/dist/commands/porch/protocol-loader.js +0 -249
- package/dist/commands/porch/protocol-loader.js.map +0 -1
- package/dist/commands/porch/signal-parser.d.ts +0 -88
- package/dist/commands/porch/signal-parser.d.ts.map +0 -1
- package/dist/commands/porch/signal-parser.js +0 -148
- package/dist/commands/porch/signal-parser.js.map +0 -1
- package/dist/commands/tower.d.ts +0 -16
- package/dist/commands/tower.d.ts.map +0 -1
- package/dist/commands/tower.js +0 -21
- package/dist/commands/tower.js.map +0 -1
- package/skeleton/config.json +0 -7
- package/skeleton/porch/protocols/bugfix.json +0 -85
- package/skeleton/porch/protocols/spider.json +0 -135
- package/skeleton/porch/protocols/tick.json +0 -76
- package/skeleton/protocols/spider/prompts/defend.md +0 -215
- package/skeleton/protocols/spider/prompts/evaluate.md +0 -241
- package/templates/dashboard/css/activity.css +0 -151
- package/templates/dashboard/js/activity.js +0 -112
package/templates/tower.html
CHANGED
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
<html lang="en">
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
|
|
6
|
+
<meta name="apple-mobile-web-app-capable" content="yes">
|
|
7
|
+
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
|
8
|
+
<meta name="theme-color" content="#252525">
|
|
6
9
|
<title>AF Control Tower</title>
|
|
7
10
|
<style>
|
|
8
11
|
* {
|
|
@@ -199,6 +202,36 @@
|
|
|
199
202
|
overflow: hidden;
|
|
200
203
|
}
|
|
201
204
|
|
|
205
|
+
.instance.gate-pending {
|
|
206
|
+
border-color: #f59e0b;
|
|
207
|
+
animation: gate-pulse 2s infinite;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
@keyframes gate-pulse {
|
|
211
|
+
0%, 100% { border-color: #f59e0b; }
|
|
212
|
+
50% { border-color: #d97706; }
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
.gate-indicator {
|
|
216
|
+
padding: 8px 20px;
|
|
217
|
+
background: rgba(245, 158, 11, 0.15);
|
|
218
|
+
border-bottom: 1px solid var(--border);
|
|
219
|
+
font-size: 14px;
|
|
220
|
+
color: #f59e0b;
|
|
221
|
+
display: flex;
|
|
222
|
+
align-items: center;
|
|
223
|
+
gap: 8px;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.gate-indicator .gate-name {
|
|
227
|
+
font-weight: 600;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
.gate-indicator .gate-builder {
|
|
231
|
+
color: var(--text-muted);
|
|
232
|
+
font-size: 12px;
|
|
233
|
+
}
|
|
234
|
+
|
|
202
235
|
.instance-header {
|
|
203
236
|
display: flex;
|
|
204
237
|
justify-content: space-between;
|
|
@@ -611,6 +644,132 @@
|
|
|
611
644
|
}
|
|
612
645
|
}
|
|
613
646
|
|
|
647
|
+
/* Mobile optimizations */
|
|
648
|
+
@media (max-width: 600px) {
|
|
649
|
+
body {
|
|
650
|
+
padding-bottom: env(safe-area-inset-bottom, 0);
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
.header {
|
|
654
|
+
padding: 16px;
|
|
655
|
+
padding-top: calc(16px + env(safe-area-inset-top, 0));
|
|
656
|
+
flex-wrap: wrap;
|
|
657
|
+
gap: 12px;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
.header h1 {
|
|
661
|
+
font-size: 18px;
|
|
662
|
+
width: 100%;
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
.header h1 .emoji {
|
|
666
|
+
font-size: 22px;
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
.header-actions {
|
|
670
|
+
width: 100%;
|
|
671
|
+
justify-content: flex-end;
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
.main {
|
|
675
|
+
padding: 16px;
|
|
676
|
+
padding-left: calc(16px + env(safe-area-inset-left, 0));
|
|
677
|
+
padding-right: calc(16px + env(safe-area-inset-right, 0));
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
.btn {
|
|
681
|
+
min-height: 44px;
|
|
682
|
+
min-width: 44px;
|
|
683
|
+
padding: 12px 16px;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
.btn-small {
|
|
687
|
+
min-height: 44px;
|
|
688
|
+
padding: 10px 14px;
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
.instance-header {
|
|
692
|
+
flex-direction: column;
|
|
693
|
+
align-items: flex-start;
|
|
694
|
+
gap: 12px;
|
|
695
|
+
padding: 16px;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
.instance-actions {
|
|
699
|
+
width: 100%;
|
|
700
|
+
justify-content: flex-end;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
.port-item {
|
|
704
|
+
flex-direction: column;
|
|
705
|
+
align-items: flex-start;
|
|
706
|
+
gap: 8px;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
.port-actions {
|
|
710
|
+
width: 100%;
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
.port-actions a {
|
|
714
|
+
min-height: 44px;
|
|
715
|
+
display: flex;
|
|
716
|
+
align-items: center;
|
|
717
|
+
justify-content: center;
|
|
718
|
+
flex: 1;
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
.launch-section {
|
|
722
|
+
padding: 16px;
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
.launch-form {
|
|
726
|
+
flex-direction: column;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
.launch-form input[type="text"] {
|
|
730
|
+
min-height: 44px;
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
.btn-launch {
|
|
734
|
+
width: 100%;
|
|
735
|
+
min-height: 44px;
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
.recent-item {
|
|
739
|
+
flex-direction: column;
|
|
740
|
+
align-items: flex-start;
|
|
741
|
+
gap: 12px;
|
|
742
|
+
padding: 16px;
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
.dialog-box {
|
|
746
|
+
min-width: auto;
|
|
747
|
+
width: calc(100% - 32px);
|
|
748
|
+
margin: 16px;
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
.toast-container {
|
|
752
|
+
left: 16px;
|
|
753
|
+
right: 16px;
|
|
754
|
+
bottom: calc(16px + env(safe-area-inset-bottom, 0));
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
/* Touch-friendly tap targets */
|
|
759
|
+
@media (pointer: coarse) {
|
|
760
|
+
.btn, .port-actions a, .autocomplete-item, .recent-item {
|
|
761
|
+
min-height: 44px;
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
.copy-btn {
|
|
765
|
+
min-width: 44px;
|
|
766
|
+
min-height: 44px;
|
|
767
|
+
display: flex;
|
|
768
|
+
align-items: center;
|
|
769
|
+
justify-content: center;
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
|
|
614
773
|
/* Dialog styles */
|
|
615
774
|
.dialog-overlay {
|
|
616
775
|
position: fixed;
|
|
@@ -680,6 +839,7 @@
|
|
|
680
839
|
Agent Farm Control Tower
|
|
681
840
|
</h1>
|
|
682
841
|
<div class="header-actions">
|
|
842
|
+
<button class="btn" id="share-btn" onclick="showShareDialog()" style="display: none;" title="Share via QR code">📱 Share</button>
|
|
683
843
|
<button class="btn" onclick="refresh()">Refresh</button>
|
|
684
844
|
</div>
|
|
685
845
|
</header>
|
|
@@ -733,6 +893,23 @@
|
|
|
733
893
|
</div>
|
|
734
894
|
</div>
|
|
735
895
|
</div>
|
|
896
|
+
|
|
897
|
+
<!-- Share Dialog (QR Code) -->
|
|
898
|
+
<div class="dialog-overlay" id="share-dialog" style="display: none;">
|
|
899
|
+
<div class="dialog-box" style="text-align: center;">
|
|
900
|
+
<h3>📱 Share via QR Code</h3>
|
|
901
|
+
<div id="share-content">
|
|
902
|
+
<div class="loading">
|
|
903
|
+
<div class="spinner"></div>
|
|
904
|
+
<p>Starting tunnel...</p>
|
|
905
|
+
</div>
|
|
906
|
+
</div>
|
|
907
|
+
<div class="dialog-actions" style="margin-top: 16px;">
|
|
908
|
+
<button class="btn" onclick="hideShareDialog()">Close</button>
|
|
909
|
+
<button class="btn" id="stop-tunnel-btn" onclick="stopTunnelAndClose()" style="display: none;">Stop Tunnel</button>
|
|
910
|
+
</div>
|
|
911
|
+
</div>
|
|
912
|
+
</div>
|
|
736
913
|
</main>
|
|
737
914
|
|
|
738
915
|
<div class="toast-container" id="toast-container"></div>
|
|
@@ -742,17 +919,153 @@
|
|
|
742
919
|
let runningInstances = [];
|
|
743
920
|
let recentInstances = [];
|
|
744
921
|
|
|
922
|
+
// Auth helper: get headers with auth token if available
|
|
923
|
+
function getAuthHeaders() {
|
|
924
|
+
const key = localStorage.getItem('codev_web_key');
|
|
925
|
+
return key ? { 'Authorization': `Bearer ${key}` } : {};
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
// Auth helper: make authenticated fetch request
|
|
929
|
+
async function authFetch(url, options = {}) {
|
|
930
|
+
const headers = { ...getAuthHeaders(), ...(options.headers || {}) };
|
|
931
|
+
const response = await fetch(url, { ...options, headers });
|
|
932
|
+
|
|
933
|
+
// If 401, clear key and redirect to login
|
|
934
|
+
if (response.status === 401) {
|
|
935
|
+
localStorage.removeItem('codev_web_key');
|
|
936
|
+
location.reload();
|
|
937
|
+
throw new Error('Unauthorized');
|
|
938
|
+
}
|
|
939
|
+
return response;
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
// Logout function
|
|
943
|
+
function logout() {
|
|
944
|
+
localStorage.removeItem('codev_web_key');
|
|
945
|
+
window.location.href = '/';
|
|
946
|
+
}
|
|
947
|
+
|
|
745
948
|
// Initialize
|
|
746
949
|
async function init() {
|
|
950
|
+
// Check if cloudflared is available and show share button
|
|
951
|
+
try {
|
|
952
|
+
const tunnelRes = await fetch('/api/tunnel/status');
|
|
953
|
+
const tunnelStatus = await tunnelRes.json();
|
|
954
|
+
if (tunnelStatus.available) {
|
|
955
|
+
document.getElementById('share-btn').style.display = 'inline-block';
|
|
956
|
+
}
|
|
957
|
+
} catch (e) {
|
|
958
|
+
// Tunnel not available, button stays hidden
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
// Request notification permission
|
|
962
|
+
if ('Notification' in window && Notification.permission === 'default') {
|
|
963
|
+
try {
|
|
964
|
+
await Notification.requestPermission();
|
|
965
|
+
} catch (e) {
|
|
966
|
+
// Ignore errors, notifications are optional
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
// Subscribe to SSE for push notifications
|
|
971
|
+
subscribeToEvents();
|
|
972
|
+
|
|
747
973
|
await refresh();
|
|
748
974
|
// Poll every 5 seconds
|
|
749
975
|
setInterval(refresh, 5000);
|
|
750
976
|
}
|
|
751
977
|
|
|
978
|
+
// SSE subscription for real-time notifications
|
|
979
|
+
// Uses fetch + ReadableStream to support Authorization header
|
|
980
|
+
let sseController = null;
|
|
981
|
+
|
|
982
|
+
async function subscribeToEvents() {
|
|
983
|
+
// Abort any existing connection
|
|
984
|
+
if (sseController) {
|
|
985
|
+
sseController.abort();
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
sseController = new AbortController();
|
|
989
|
+
|
|
990
|
+
try {
|
|
991
|
+
const response = await fetch('/api/events', {
|
|
992
|
+
headers: getAuthHeaders(),
|
|
993
|
+
signal: sseController.signal,
|
|
994
|
+
});
|
|
995
|
+
|
|
996
|
+
if (!response.ok) {
|
|
997
|
+
console.log('SSE connection failed:', response.status);
|
|
998
|
+
setTimeout(subscribeToEvents, 5000);
|
|
999
|
+
return;
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
const reader = response.body.getReader();
|
|
1003
|
+
const decoder = new TextDecoder();
|
|
1004
|
+
let buffer = '';
|
|
1005
|
+
|
|
1006
|
+
while (true) {
|
|
1007
|
+
const { done, value } = await reader.read();
|
|
1008
|
+
|
|
1009
|
+
if (done) {
|
|
1010
|
+
console.log('SSE stream ended, reconnecting...');
|
|
1011
|
+
setTimeout(subscribeToEvents, 5000);
|
|
1012
|
+
return;
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
buffer += decoder.decode(value, { stream: true });
|
|
1016
|
+
|
|
1017
|
+
// Parse SSE format: "data: {...}\n\n"
|
|
1018
|
+
const lines = buffer.split('\n\n');
|
|
1019
|
+
buffer = lines.pop() || ''; // Keep incomplete message in buffer
|
|
1020
|
+
|
|
1021
|
+
for (const chunk of lines) {
|
|
1022
|
+
const dataMatch = chunk.match(/^data:\s*(.+)$/m);
|
|
1023
|
+
if (!dataMatch) continue;
|
|
1024
|
+
|
|
1025
|
+
try {
|
|
1026
|
+
const data = JSON.parse(dataMatch[1]);
|
|
1027
|
+
|
|
1028
|
+
if (data.type === 'connected') {
|
|
1029
|
+
console.log('SSE connected:', data.id);
|
|
1030
|
+
continue;
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
// Show browser notification
|
|
1034
|
+
if ('Notification' in window && Notification.permission === 'granted') {
|
|
1035
|
+
const notification = new Notification(data.title, {
|
|
1036
|
+
body: data.body,
|
|
1037
|
+
icon: '/favicon.ico',
|
|
1038
|
+
tag: 'tower-notification-' + data.id,
|
|
1039
|
+
});
|
|
1040
|
+
|
|
1041
|
+
// Auto-close after 5 seconds
|
|
1042
|
+
setTimeout(() => notification.close(), 5000);
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
// Also show in-app toast
|
|
1046
|
+
showToast(`${data.title}: ${data.body}`, data.type || 'info');
|
|
1047
|
+
|
|
1048
|
+
// Refresh to show updated status
|
|
1049
|
+
refresh();
|
|
1050
|
+
} catch (e) {
|
|
1051
|
+
console.error('SSE parse error:', e);
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
} catch (e) {
|
|
1056
|
+
if (e.name === 'AbortError') {
|
|
1057
|
+
// Intentional abort, don't reconnect
|
|
1058
|
+
return;
|
|
1059
|
+
}
|
|
1060
|
+
console.error('SSE error:', e);
|
|
1061
|
+
setTimeout(subscribeToEvents, 5000);
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
|
|
752
1065
|
// Refresh data from API
|
|
753
1066
|
async function refresh() {
|
|
754
1067
|
try {
|
|
755
|
-
const response = await
|
|
1068
|
+
const response = await authFetch('/api/status');
|
|
756
1069
|
if (!response.ok) throw new Error('Failed to fetch status');
|
|
757
1070
|
|
|
758
1071
|
const data = await response.json();
|
|
@@ -774,7 +1087,7 @@
|
|
|
774
1087
|
<div class="empty-state">
|
|
775
1088
|
<div class="icon">📭</div>
|
|
776
1089
|
<h2>No running instances</h2>
|
|
777
|
-
<p>Start a new instance below or run <code>af start</code> in a project directory.</p>
|
|
1090
|
+
<p>Start a new instance below or run <code>af dash start</code> in a project directory.</p>
|
|
778
1091
|
</div>
|
|
779
1092
|
`;
|
|
780
1093
|
} else {
|
|
@@ -810,28 +1123,54 @@
|
|
|
810
1123
|
function renderInstance(instance) {
|
|
811
1124
|
const statusClass = instance.running ? 'running' : 'stopped';
|
|
812
1125
|
const statusText = instance.running ? 'Running' : 'Stopped';
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
1126
|
+
const hasGate = instance.gateStatus?.hasGate;
|
|
1127
|
+
|
|
1128
|
+
// Render terminals list (Architect, Builders, Shells)
|
|
1129
|
+
const terminals = instance.terminals || [];
|
|
1130
|
+
let terminalsHtml = '';
|
|
1131
|
+
|
|
1132
|
+
if (instance.running && terminals.length > 0) {
|
|
1133
|
+
// Show each terminal as a link
|
|
1134
|
+
terminalsHtml = terminals.map(terminal => `
|
|
1135
|
+
<div class="port-item">
|
|
1136
|
+
<div class="port-info">
|
|
1137
|
+
<span class="port-status ${terminal.active ? 'active' : 'inactive'}"></span>
|
|
1138
|
+
<span class="port-type">${escapeHtml(terminal.label)}</span>
|
|
1139
|
+
</div>
|
|
1140
|
+
<div class="port-actions">
|
|
1141
|
+
<a href="${escapeHtml(terminal.url)}" target="_blank">Open</a>
|
|
1142
|
+
</div>
|
|
820
1143
|
</div>
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
1144
|
+
`).join('');
|
|
1145
|
+
} else if (instance.running) {
|
|
1146
|
+
// Fallback to Dashboard link if no terminals available
|
|
1147
|
+
terminalsHtml = `
|
|
1148
|
+
<div class="port-item">
|
|
1149
|
+
<div class="port-info">
|
|
1150
|
+
<span class="port-status active"></span>
|
|
1151
|
+
<span class="port-type">Dashboard</span>
|
|
1152
|
+
</div>
|
|
1153
|
+
<div class="port-actions">
|
|
1154
|
+
<a href="${escapeHtml(instance.proxyUrl)}" target="_blank">Open</a>
|
|
1155
|
+
</div>
|
|
825
1156
|
</div>
|
|
826
|
-
|
|
827
|
-
|
|
1157
|
+
`;
|
|
1158
|
+
}
|
|
828
1159
|
|
|
829
1160
|
const lastUsed = instance.lastUsed
|
|
830
1161
|
? formatDate(instance.lastUsed)
|
|
831
1162
|
: 'Never';
|
|
832
1163
|
|
|
1164
|
+
const gateIndicatorHtml = hasGate ? `
|
|
1165
|
+
<div class="gate-indicator">
|
|
1166
|
+
<span>⏳</span>
|
|
1167
|
+
<span class="gate-name">${escapeHtml(instance.gateStatus.gateName || 'approval')}</span>
|
|
1168
|
+
${instance.gateStatus.builderId ? `<span class="gate-builder">(${escapeHtml(instance.gateStatus.builderId)})</span>` : ''}
|
|
1169
|
+
</div>
|
|
1170
|
+
` : '';
|
|
1171
|
+
|
|
833
1172
|
return `
|
|
834
|
-
<div class="instance">
|
|
1173
|
+
<div class="instance ${hasGate ? 'gate-pending' : ''}" data-project="${escapeHtml(instance.projectPath)}">
|
|
835
1174
|
<div class="instance-header">
|
|
836
1175
|
<div class="instance-title">
|
|
837
1176
|
<span class="instance-name">${escapeHtml(instance.projectName)}</span>
|
|
@@ -849,6 +1188,7 @@
|
|
|
849
1188
|
`}
|
|
850
1189
|
</div>
|
|
851
1190
|
</div>
|
|
1191
|
+
${gateIndicatorHtml}
|
|
852
1192
|
<div class="instance-path-row">
|
|
853
1193
|
<span class="instance-path" title="${escapeHtml(instance.projectPath)}">
|
|
854
1194
|
${escapeHtml(instance.projectPath)}
|
|
@@ -857,11 +1197,10 @@
|
|
|
857
1197
|
</div>
|
|
858
1198
|
<div class="instance-body">
|
|
859
1199
|
<div class="ports-list">
|
|
860
|
-
${
|
|
1200
|
+
${terminalsHtml}
|
|
861
1201
|
</div>
|
|
862
1202
|
<div class="instance-meta">
|
|
863
1203
|
<span>Last active: ${lastUsed}</span>
|
|
864
|
-
<span>Port block: ${instance.basePort}-${instance.basePort + 99}</span>
|
|
865
1204
|
</div>
|
|
866
1205
|
</div>
|
|
867
1206
|
</div>
|
|
@@ -952,7 +1291,7 @@
|
|
|
952
1291
|
}
|
|
953
1292
|
|
|
954
1293
|
try {
|
|
955
|
-
const response = await
|
|
1294
|
+
const response = await authFetch('/api/browse?path=' + encodeURIComponent(inputPath));
|
|
956
1295
|
const data = await response.json();
|
|
957
1296
|
suggestions = data.suggestions || [];
|
|
958
1297
|
selectedIndex = -1;
|
|
@@ -1007,7 +1346,7 @@
|
|
|
1007
1346
|
// Launch a specific path (from recents)
|
|
1008
1347
|
async function launchPath(projectPath) {
|
|
1009
1348
|
try {
|
|
1010
|
-
const response = await
|
|
1349
|
+
const response = await authFetch('/api/launch', {
|
|
1011
1350
|
method: 'POST',
|
|
1012
1351
|
headers: { 'Content-Type': 'application/json' },
|
|
1013
1352
|
body: JSON.stringify({ projectPath })
|
|
@@ -1033,7 +1372,7 @@
|
|
|
1033
1372
|
// Stop an instance by port
|
|
1034
1373
|
async function stopInstance(basePort) {
|
|
1035
1374
|
try {
|
|
1036
|
-
const response = await
|
|
1375
|
+
const response = await authFetch('/api/stop', {
|
|
1037
1376
|
method: 'POST',
|
|
1038
1377
|
headers: { 'Content-Type': 'application/json' },
|
|
1039
1378
|
body: JSON.stringify({ basePort })
|
|
@@ -1056,7 +1395,7 @@
|
|
|
1056
1395
|
async function restartInstance(basePort, projectPath) {
|
|
1057
1396
|
try {
|
|
1058
1397
|
// First stop
|
|
1059
|
-
await
|
|
1398
|
+
await authFetch('/api/stop', {
|
|
1060
1399
|
method: 'POST',
|
|
1061
1400
|
headers: { 'Content-Type': 'application/json' },
|
|
1062
1401
|
body: JSON.stringify({ basePort })
|
|
@@ -1066,7 +1405,7 @@
|
|
|
1066
1405
|
await new Promise(r => setTimeout(r, 1000));
|
|
1067
1406
|
|
|
1068
1407
|
// Then start
|
|
1069
|
-
const response = await
|
|
1408
|
+
const response = await authFetch('/api/launch', {
|
|
1070
1409
|
method: 'POST',
|
|
1071
1410
|
headers: { 'Content-Type': 'application/json' },
|
|
1072
1411
|
body: JSON.stringify({ projectPath })
|
|
@@ -1096,7 +1435,7 @@
|
|
|
1096
1435
|
}
|
|
1097
1436
|
|
|
1098
1437
|
try {
|
|
1099
|
-
const response = await
|
|
1438
|
+
const response = await authFetch('/api/launch', {
|
|
1100
1439
|
method: 'POST',
|
|
1101
1440
|
headers: { 'Content-Type': 'application/json' },
|
|
1102
1441
|
body: JSON.stringify({ projectPath })
|
|
@@ -1170,6 +1509,23 @@
|
|
|
1170
1509
|
.replace(/'/g, ''');
|
|
1171
1510
|
}
|
|
1172
1511
|
|
|
1512
|
+
// Base64URL encoding (RFC 4648) for project paths
|
|
1513
|
+
// IMPORTANT: Use TextEncoder for Unicode support (btoa only handles Latin-1)
|
|
1514
|
+
function toBase64URL(str) {
|
|
1515
|
+
// Encode string to UTF-8 bytes, then to Base64, then to Base64URL
|
|
1516
|
+
const bytes = new TextEncoder().encode(str);
|
|
1517
|
+
const base64 = btoa(String.fromCharCode(...bytes));
|
|
1518
|
+
return base64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
|
1519
|
+
}
|
|
1520
|
+
|
|
1521
|
+
// Generate proxy URL for a project
|
|
1522
|
+
// All terminals are now multiplexed on a single port via WebSocket (Spec 0085)
|
|
1523
|
+
// The React dashboard handles tab selection internally
|
|
1524
|
+
function getProxyUrl(instance, portType) {
|
|
1525
|
+
const encodedPath = toBase64URL(instance.projectPath);
|
|
1526
|
+
return `/project/${encodedPath}/`;
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1173
1529
|
// Toast notifications
|
|
1174
1530
|
function showToast(message, type = 'info') {
|
|
1175
1531
|
const container = document.getElementById('toast-container');
|
|
@@ -1183,6 +1539,121 @@
|
|
|
1183
1539
|
}, 4000);
|
|
1184
1540
|
}
|
|
1185
1541
|
|
|
1542
|
+
// Share dialog functions (QR code for mobile access)
|
|
1543
|
+
let tunnelAbortController = null;
|
|
1544
|
+
|
|
1545
|
+
async function showShareDialog() {
|
|
1546
|
+
const dialog = document.getElementById('share-dialog');
|
|
1547
|
+
const content = document.getElementById('share-content');
|
|
1548
|
+
const stopBtn = document.getElementById('stop-tunnel-btn');
|
|
1549
|
+
|
|
1550
|
+
dialog.style.display = 'flex';
|
|
1551
|
+
stopBtn.style.display = 'none';
|
|
1552
|
+
|
|
1553
|
+
// Create abort controller for cancellation
|
|
1554
|
+
tunnelAbortController = new AbortController();
|
|
1555
|
+
|
|
1556
|
+
content.innerHTML = `
|
|
1557
|
+
<div class="loading">
|
|
1558
|
+
<div class="spinner"></div>
|
|
1559
|
+
<p>Starting tunnel...</p>
|
|
1560
|
+
<p style="font-size: 12px; color: var(--muted); margin-top: 8px;">This may take up to 30 seconds</p>
|
|
1561
|
+
<button class="btn" style="margin-top: 16px;" onclick="cancelTunnelStart()">Cancel</button>
|
|
1562
|
+
</div>
|
|
1563
|
+
`;
|
|
1564
|
+
|
|
1565
|
+
try {
|
|
1566
|
+
// Check if tunnel is already running
|
|
1567
|
+
const statusRes = await fetch('/api/tunnel/status', { signal: tunnelAbortController.signal });
|
|
1568
|
+
const status = await statusRes.json();
|
|
1569
|
+
|
|
1570
|
+
if (status.running && status.url) {
|
|
1571
|
+
showQRCode(status.url);
|
|
1572
|
+
return;
|
|
1573
|
+
}
|
|
1574
|
+
|
|
1575
|
+
// Start tunnel
|
|
1576
|
+
const res = await fetch('/api/tunnel/start', { method: 'POST', signal: tunnelAbortController.signal });
|
|
1577
|
+
const result = await res.json();
|
|
1578
|
+
|
|
1579
|
+
if (result.success && result.url) {
|
|
1580
|
+
showQRCode(result.url);
|
|
1581
|
+
} else {
|
|
1582
|
+
content.innerHTML = `<p style="color: var(--danger);">Failed to start tunnel: ${result.error || 'Unknown error'}</p>`;
|
|
1583
|
+
}
|
|
1584
|
+
} catch (e) {
|
|
1585
|
+
if (e.name === 'AbortError') {
|
|
1586
|
+
content.innerHTML = '<p>Tunnel start cancelled.</p>';
|
|
1587
|
+
} else {
|
|
1588
|
+
content.innerHTML = `<p style="color: var(--danger);">Error: ${e.message}</p>`;
|
|
1589
|
+
}
|
|
1590
|
+
} finally {
|
|
1591
|
+
tunnelAbortController = null;
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
1594
|
+
|
|
1595
|
+
function cancelTunnelStart() {
|
|
1596
|
+
if (tunnelAbortController) {
|
|
1597
|
+
tunnelAbortController.abort();
|
|
1598
|
+
}
|
|
1599
|
+
// Also stop any tunnel that might have started
|
|
1600
|
+
fetch('/api/tunnel/stop', { method: 'POST' }).catch(() => {});
|
|
1601
|
+
}
|
|
1602
|
+
|
|
1603
|
+
function showQRCode(tunnelUrl) {
|
|
1604
|
+
const content = document.getElementById('share-content');
|
|
1605
|
+
const stopBtn = document.getElementById('stop-tunnel-btn');
|
|
1606
|
+
|
|
1607
|
+
// Generate QR code using qrcode.js (loaded from CDN)
|
|
1608
|
+
content.innerHTML = `
|
|
1609
|
+
<p style="margin-bottom: 16px;">Scan to access from mobile:</p>
|
|
1610
|
+
<div id="qrcode" style="display: inline-block; padding: 16px; background: white; border-radius: 8px;"></div>
|
|
1611
|
+
<p style="margin-top: 16px; font-size: 12px; color: var(--muted);">
|
|
1612
|
+
<a href="${tunnelUrl}" target="_blank" style="color: var(--primary);">${tunnelUrl}</a>
|
|
1613
|
+
</p>
|
|
1614
|
+
`;
|
|
1615
|
+
|
|
1616
|
+
// Load QRCode library and generate
|
|
1617
|
+
if (!window.QRCode) {
|
|
1618
|
+
const script = document.createElement('script');
|
|
1619
|
+
script.src = 'https://cdn.jsdelivr.net/npm/qrcodejs@1.0.0/qrcode.min.js';
|
|
1620
|
+
script.onload = () => generateQR(tunnelUrl);
|
|
1621
|
+
document.head.appendChild(script);
|
|
1622
|
+
} else {
|
|
1623
|
+
generateQR(tunnelUrl);
|
|
1624
|
+
}
|
|
1625
|
+
|
|
1626
|
+
stopBtn.style.display = 'inline-block';
|
|
1627
|
+
}
|
|
1628
|
+
|
|
1629
|
+
function generateQR(url) {
|
|
1630
|
+
const container = document.getElementById('qrcode');
|
|
1631
|
+
if (container && window.QRCode) {
|
|
1632
|
+
container.innerHTML = '';
|
|
1633
|
+
new QRCode(container, {
|
|
1634
|
+
text: url,
|
|
1635
|
+
width: 200,
|
|
1636
|
+
height: 200,
|
|
1637
|
+
colorDark: '#000000',
|
|
1638
|
+
colorLight: '#ffffff',
|
|
1639
|
+
});
|
|
1640
|
+
}
|
|
1641
|
+
}
|
|
1642
|
+
|
|
1643
|
+
function hideShareDialog() {
|
|
1644
|
+
document.getElementById('share-dialog').style.display = 'none';
|
|
1645
|
+
}
|
|
1646
|
+
|
|
1647
|
+
async function stopTunnelAndClose() {
|
|
1648
|
+
try {
|
|
1649
|
+
await fetch('/api/tunnel/stop', { method: 'POST' });
|
|
1650
|
+
} catch (e) {
|
|
1651
|
+
// Ignore
|
|
1652
|
+
}
|
|
1653
|
+
hideShareDialog();
|
|
1654
|
+
showToast('Tunnel stopped', 'success');
|
|
1655
|
+
}
|
|
1656
|
+
|
|
1186
1657
|
// Create project dialog functions
|
|
1187
1658
|
function showCreateProjectDialog() {
|
|
1188
1659
|
const dialog = document.getElementById('create-dialog');
|
|
@@ -1219,7 +1690,7 @@
|
|
|
1219
1690
|
hideCreateProjectDialog();
|
|
1220
1691
|
|
|
1221
1692
|
try {
|
|
1222
|
-
const response = await
|
|
1693
|
+
const response = await authFetch('/api/create', {
|
|
1223
1694
|
method: 'POST',
|
|
1224
1695
|
headers: { 'Content-Type': 'application/json' },
|
|
1225
1696
|
body: JSON.stringify({ parent, name })
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Kickoff command - Start a new protocol-driven project
|
|
3
|
-
*
|
|
4
|
-
* This command combines:
|
|
5
|
-
* 1. Creating a git worktree
|
|
6
|
-
* 2. Initializing porch state
|
|
7
|
-
* 3. Starting the porch loop in the builder
|
|
8
|
-
*/
|
|
9
|
-
export interface KickoffOptions {
|
|
10
|
-
project: string;
|
|
11
|
-
protocol?: string;
|
|
12
|
-
noRole?: boolean;
|
|
13
|
-
resume?: boolean;
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* Kickoff a new protocol-driven project
|
|
17
|
-
*/
|
|
18
|
-
export declare function kickoff(options: KickoffOptions): Promise<void>;
|
|
19
|
-
//# sourceMappingURL=kickoff.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"kickoff.d.ts","sourceRoot":"","sources":["../../../src/agent-farm/commands/kickoff.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAYH,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAqKD;;GAEG;AACH,wBAAsB,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CA6MpE"}
|