@kortix/sandbox 0.4.1 → 0.4.3

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.
@@ -14,130 +14,117 @@ if [ -f "$MARKER" ]; then
14
14
  exit 0
15
15
  fi
16
16
 
17
- echo "[heyagi] Applying desktop customization..."
18
- mkdir -p "$CONFIG_DIR/.config/autostart"
19
- mkdir -p "$CONFIG_DIR/.local/share/konsole"
17
+ echo "[heyagi] Applying XFCE desktop customization (Alpine)..."
20
18
 
21
19
  # ── Symlink presentations into Desktop for easy access ─────────────────────
22
20
  mkdir -p "$CONFIG_DIR/presentations"
23
- # Create a Desktop directory for KDE and symlink presentations into it
24
21
  mkdir -p "$CONFIG_DIR/Desktop"
25
22
  ln -sfn "$CONFIG_DIR/presentations" "$CONFIG_DIR/Desktop/presentations"
26
23
 
27
- # ── KDE Global: Breeze Dark ────────────────────────────────────────────────
28
- cat > "$CONFIG_DIR/.config/kdeglobals" << 'EOF'
29
- [General]
30
- ColorScheme=BreezeDark
31
- Name=Breeze Dark
32
- widgetStyle=Breeze
33
-
34
- [Icons]
35
- Theme=breeze-dark
36
-
37
- [KDE]
38
- LookAndFeelPackage=org.kde.breezedark.desktop
39
- widgetStyle=breeze
24
+ # ── XFCE: Wallpaper ───────────────────────────────────────────────────────
25
+ mkdir -p "$CONFIG_DIR/.config/xfce4/xfconf/xfce-perchannel-xml"
26
+ cat > "$CONFIG_DIR/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-desktop.xml" << 'EOF'
27
+ <?xml version="1.0" encoding="UTF-8"?>
28
+ <channel name="xfce4-desktop" version="1.0">
29
+ <property name="backdrop" type="empty">
30
+ <property name="screen0" type="empty">
31
+ <property name="monitorVNC-0" type="empty">
32
+ <property name="workspace0" type="empty">
33
+ <property name="last-image" type="string" value="/usr/share/wallpapers/heyagi/wallpaper.png"/>
34
+ <property name="image-style" type="int" value="5"/>
35
+ <property name="color-style" type="int" value="0"/>
36
+ <property name="rgba1" type="array">
37
+ <value type="double" value="0.10196"/>
38
+ <value type="double" value="0.10588"/>
39
+ <value type="double" value="0.14902"/>
40
+ <value type="double" value="1.0"/>
41
+ </property>
42
+ </property>
43
+ </property>
44
+ <property name="monitorscreen" type="empty">
45
+ <property name="workspace0" type="empty">
46
+ <property name="last-image" type="string" value="/usr/share/wallpapers/heyagi/wallpaper.png"/>
47
+ <property name="image-style" type="int" value="5"/>
48
+ <property name="color-style" type="int" value="0"/>
49
+ <property name="rgba1" type="array">
50
+ <value type="double" value="0.10196"/>
51
+ <value type="double" value="0.10588"/>
52
+ <value type="double" value="0.14902"/>
53
+ <value type="double" value="1.0"/>
54
+ </property>
55
+ </property>
56
+ </property>
57
+ </property>
58
+ </property>
59
+ </channel>
40
60
  EOF
41
61
 
42
- # ── KWin ────────────────────────────────────────────────────────────────────
43
- cat > "$CONFIG_DIR/.config/kwinrc" << 'EOF'
44
- [org.kde.kdecoration2]
45
- theme=Breeze
46
- library=org.kde.breeze
47
-
48
- [Windows]
49
- Placement=Centered
50
-
51
- [Desktops]
52
- Number=1
53
- Rows=1
62
+ # ── XFCE: Dark theme (adw-gtk3-dark — Alpine's equivalent of Adwaita-dark)
63
+ cat > "$CONFIG_DIR/.config/xfce4/xfconf/xfce-perchannel-xml/xsettings.xml" << 'EOF'
64
+ <?xml version="1.0" encoding="UTF-8"?>
65
+ <channel name="xsettings" version="1.0">
66
+ <property name="Net" type="empty">
67
+ <property name="ThemeName" type="string" value="adw-gtk3-dark"/>
68
+ <property name="IconThemeName" type="string" value="Adwaita"/>
69
+ <property name="CursorThemeName" type="string" value="Breeze_Light"/>
70
+ </property>
71
+ <property name="Gtk" type="empty">
72
+ <property name="FontName" type="string" value="Sans 10"/>
73
+ <property name="CursorThemeSize" type="int" value="24"/>
74
+ </property>
75
+ </channel>
54
76
  EOF
55
77
 
56
- # ── Plasma theme ────────────────────────────────────────────────────────────
57
- cat > "$CONFIG_DIR/.config/plasmarc" << 'EOF'
58
- [Theme]
59
- name=breeze-dark
78
+ # ── XFCE: Window Manager dark theme (Daloa — only xfwm4 theme on Alpine)
79
+ cat > "$CONFIG_DIR/.config/xfce4/xfconf/xfce-perchannel-xml/xfwm4.xml" << 'EOF'
80
+ <?xml version="1.0" encoding="UTF-8"?>
81
+ <channel name="xfwm4" version="1.0">
82
+ <property name="general" type="empty">
83
+ <property name="theme" type="string" value="Daloa"/>
84
+ <property name="title_font" type="string" value="Sans Bold 9"/>
85
+ <property name="placement_ratio" type="int" value="50"/>
86
+ <property name="cycle_tabwin_mode" type="int" value="0"/>
87
+ </property>
88
+ </channel>
60
89
  EOF
61
90
 
62
- # ── Konsole dark profile ───────────────────────────────────────────────────
63
- cat > "$CONFIG_DIR/.local/share/konsole/HeyAGI.profile" << 'EOF'
64
- [Appearance]
65
- ColorScheme=Breeze
66
- Font=Monospace,11,-1,5,50,0,0,0,0,0
67
-
68
- [General]
69
- Name=HeyAGI
70
- Parent=FALLBACK/
71
-
72
- [Scrolling]
73
- HistoryMode=2
91
+ # ── XFCE: Terminal dark profile ──────────────────────────────────────────
92
+ mkdir -p "$CONFIG_DIR/.config/xfce4/terminal"
93
+ cat > "$CONFIG_DIR/.config/xfce4/terminal/terminalrc" << 'EOF'
94
+ [Configuration]
95
+ BackgroundMode=TERMINAL_BACKGROUND_TRANSPARENT
96
+ BackgroundDarkness=0.90
97
+ ColorForeground=#c0caf5
98
+ ColorBackground=#1a1b26
99
+ ColorCursor=#c0caf5
100
+ ColorPalette=#15161e;#f7768e;#9ece6a;#e0af68;#7aa2f7;#bb9af7;#7dcfff;#a9b1d6;#414868;#f7768e;#9ece6a;#e0af68;#7aa2f7;#bb9af7;#7dcfff;#c0caf5
101
+ FontName=Monospace 11
102
+ MiscAlwaysShowTabs=FALSE
103
+ MiscBordersDefault=TRUE
104
+ MiscShowUnsafePasteDialog=FALSE
105
+ ScrollingUnlimited=TRUE
74
106
  EOF
75
107
 
76
- cat > "$CONFIG_DIR/.config/konsolerc" << 'EOF'
77
- [Desktop Entry]
78
- DefaultProfile=HeyAGI.profile
79
-
80
- [MainWindow]
81
- MenuBar=Disabled
82
- ToolBarsMovable=Disabled
108
+ # ── GTK dark theme (fallback for GTK2 apps) ───────────────────────────────
109
+ cat > "$CONFIG_DIR/.gtkrc-2.0" << 'EOF'
110
+ gtk-theme-name="adw-gtk3-dark"
111
+ gtk-icon-theme-name="Adwaita"
112
+ gtk-font-name="Sans 10"
113
+ gtk-cursor-theme-name="Breeze_Light"
83
114
  EOF
84
115
 
85
- # ── Autostart: apply wallpaper + launcher icon after KDE session loads ──────
86
- cat > "$CONFIG_DIR/.config/autostart/heyagi-desktop.desktop" << 'EOF'
87
- [Desktop Entry]
88
- Type=Application
89
- Name=HeyAGI Desktop Setup
90
- Exec=/usr/share/wallpapers/heyagi/apply-desktop.sh
91
- X-KDE-autostart-phase=2
116
+ mkdir -p "$CONFIG_DIR/.config/gtk-3.0"
117
+ cat > "$CONFIG_DIR/.config/gtk-3.0/settings.ini" << 'EOF'
118
+ [Settings]
119
+ gtk-theme-name=adw-gtk3-dark
120
+ gtk-icon-theme-name=Adwaita
121
+ gtk-font-name=Sans 10
122
+ gtk-application-prefer-dark-theme=true
123
+ gtk-cursor-theme-name=Breeze_Light
92
124
  EOF
93
125
 
94
- cat > /usr/share/wallpapers/heyagi/apply-desktop.sh << 'SCRIPT'
95
- #!/bin/bash
96
- sleep 5
97
-
98
- plasma-apply-wallpaperimage /usr/share/wallpapers/heyagi/wallpaper.png
99
-
100
- PLASMA_RC="$HOME/.config/plasma-org.kde.plasma.desktop-appletsrc"
101
- ICON_PATH="/usr/share/icons/heyagi/kortix-symbol-white.svg"
102
-
103
- if [ -f "$PLASMA_RC" ]; then
104
- # Find the kickoff applet's [Configuration][General] section and inject icon
105
- # Get the containment/applet IDs for kickoff
106
- KICKOFF_SECTION=$(grep -B3 "plugin=org.kde.plasma.kickoff" "$PLASMA_RC" | grep "^\[Containments\]" | tail -1)
107
-
108
- if [ -n "$KICKOFF_SECTION" ]; then
109
- # Build the [Configuration][General] section name
110
- GENERAL_SECTION="${KICKOFF_SECTION%]}][Configuration][General]"
111
-
112
- if grep -q "$(echo "$GENERAL_SECTION" | sed 's/\[/\\[/g; s/\]/\\]/g')" "$PLASMA_RC"; then
113
- # Section exists -- replace or add icon line
114
- ESCAPED=$(echo "$GENERAL_SECTION" | sed 's/\[/\\[/g; s/\]/\\]/g')
115
- if grep -A10 "$ESCAPED" "$PLASMA_RC" | grep -q "^icon="; then
116
- sed -i "/$ESCAPED/,/^\[/{s|^icon=.*|icon=$ICON_PATH|}" "$PLASMA_RC"
117
- else
118
- sed -i "/$ESCAPED/a icon=$ICON_PATH" "$PLASMA_RC"
119
- fi
120
- else
121
- # Section doesn't exist -- create it
122
- CONF_SECTION="${KICKOFF_SECTION%]}][Configuration]"
123
- ESCAPED_CONF=$(echo "$CONF_SECTION" | sed 's/\[/\\[/g; s/\]/\\]/g')
124
- sed -i "/$ESCAPED_CONF/,/^\[/{/^\[.*\]/!b;i\\${GENERAL_SECTION}\nicon=$ICON_PATH
125
- }" "$PLASMA_RC"
126
- fi
127
- fi
128
-
129
- # Restart plasmashell to pick up icon change
130
- kquitapp5 plasmashell 2>/dev/null
131
- sleep 2
132
- kstart5 plasmashell 2>/dev/null &
133
- fi
134
- SCRIPT
135
- chmod +x /usr/share/wallpapers/heyagi/apply-desktop.sh
136
-
137
126
  # ── Fix ownership ──────────────────────────────────────────────────────────
138
- # Give abc full ownership of everything under /workspace so opencode and its
139
- # agents can freely create directories and files (presentations, output, etc.)
140
127
  chown -R abc:abc "$CONFIG_DIR" 2>/dev/null
141
128
 
142
129
  touch "$MARKER"
143
- echo "[heyagi] Customization complete."
130
+ echo "[heyagi] XFCE customization complete."
@@ -12,11 +12,11 @@ if [ "$ENV_MODE" = "cloud" ] || [ "$ENV_MODE" = "production" ]; then
12
12
  echo "[Kortix] Services will still start; set KORTIX_API_URL later to enable model routing"
13
13
  else
14
14
  # Write env overrides that s6 services will inherit via with-contenv
15
- printf '%s' "${KORTIX_API_URL}/tavily" > /var/run/s6/container_environment/TAVILY_API_URL
16
- printf '%s' "${KORTIX_API_URL}/serper" > /var/run/s6/container_environment/SERPER_API_URL
17
- printf '%s' "${KORTIX_API_URL}/firecrawl" > /var/run/s6/container_environment/FIRECRAWL_API_URL
18
- printf '%s' "${KORTIX_API_URL}/replicate" > /var/run/s6/container_environment/REPLICATE_API_URL
19
- printf '%s' "${KORTIX_API_URL}/context7" > /var/run/s6/container_environment/CONTEXT7_API_URL
15
+ printf '%s' "${KORTIX_API_URL}/tavily" > /run/s6/container_environment/TAVILY_API_URL
16
+ printf '%s' "${KORTIX_API_URL}/serper" > /run/s6/container_environment/SERPER_API_URL
17
+ printf '%s' "${KORTIX_API_URL}/firecrawl" > /run/s6/container_environment/FIRECRAWL_API_URL
18
+ printf '%s' "${KORTIX_API_URL}/replicate" > /run/s6/container_environment/REPLICATE_API_URL
19
+ printf '%s' "${KORTIX_API_URL}/context7" > /run/s6/container_environment/CONTEXT7_API_URL
20
20
 
21
21
  echo "[Kortix] SDK URLs routed through ${KORTIX_API_URL}"
22
22
  fi
@@ -18,8 +18,18 @@ await secretStore.loadIntoProcessEnv()
18
18
  app.use('*', logger())
19
19
  app.use('*', cors())
20
20
 
21
- // Health check
22
- app.get('/kortix/health', (c) => c.json({ status: 'ok' }))
21
+ // Health check — includes current sandbox version
22
+ app.get('/kortix/health', async (c) => {
23
+ let version = '0.0.0'
24
+ try {
25
+ const file = Bun.file('/opt/kortix/.version')
26
+ if (await file.exists()) {
27
+ const data = await file.json()
28
+ version = data.version || '0.0.0'
29
+ }
30
+ } catch {}
31
+ return c.json({ status: 'ok', version })
32
+ })
23
33
 
24
34
  // Update check — /kortix/update and /kortix/update/status
25
35
  app.route('/kortix/update', updateRouter)
@@ -1,12 +1,4 @@
1
1
  import { Hono } from 'hono';
2
- import { config } from '../config';
3
-
4
- // ─── Types ──────────────────────────────────────────────────────────────────
5
-
6
- interface LocalVersion {
7
- version: string;
8
- updatedAt: string;
9
- }
10
2
 
11
3
  // ─── Constants ──────────────────────────────────────────────────────────────
12
4
 
@@ -32,35 +24,17 @@ let updateInProgress = false;
32
24
 
33
25
  // ─── Helpers ────────────────────────────────────────────────────────────────
34
26
 
35
- async function readLocalVersion(): Promise<LocalVersion> {
27
+ async function readLocalVersion(): Promise<string> {
36
28
  try {
37
29
  const file = Bun.file(VERSION_FILE);
38
30
  if (await file.exists()) {
39
- return await file.json();
31
+ const data = await file.json();
32
+ return data.version || '0.0.0';
40
33
  }
41
34
  } catch (e) {
42
35
  console.error('[Update] Failed to read version file:', e);
43
36
  }
44
- return { version: '0.0.0', updatedAt: '' };
45
- }
46
-
47
- async function fetchLatestVersion(): Promise<string | null> {
48
- const url = `${config.KORTIX_API_URL}/v1/sandbox/version`;
49
- try {
50
- const res = await fetch(url, {
51
- headers: { 'Accept': 'application/json' },
52
- signal: AbortSignal.timeout(10_000),
53
- });
54
- if (!res.ok) {
55
- console.error(`[Update] Version fetch failed: ${res.status}`);
56
- return null;
57
- }
58
- const data = await res.json() as { version: string };
59
- return data.version;
60
- } catch (e) {
61
- console.error('[Update] Failed to fetch version:', e);
62
- return null;
63
- }
37
+ return '0.0.0';
64
38
  }
65
39
 
66
40
  async function run(cmd: string): Promise<{ ok: boolean; output: string }> {
@@ -116,62 +90,45 @@ async function performUpdate(targetVersion: string): Promise<{
116
90
 
117
91
  const updateRouter = new Hono();
118
92
 
119
- /**
120
- * GET /kortix/update/status
121
- *
122
- * Returns current sandbox version + latest available version.
123
- * Frontend uses this to decide whether to show "Update available".
124
- * Read-only — does NOT trigger any update.
125
- */
126
- updateRouter.get('/status', async (c) => {
127
- const local = await readLocalVersion();
128
- const latest = await fetchLatestVersion();
129
-
130
- return c.json({
131
- currentVersion: local.version,
132
- latestVersion: latest || 'unknown',
133
- updateAvailable: latest ? local.version !== latest : false,
134
- updatedAt: local.updatedAt,
135
- updateInProgress,
136
- });
137
- });
138
-
139
93
  /**
140
94
  * POST /kortix/update
141
95
  *
142
- * User-triggered update. Fetches latest version, installs the package,
143
- * restarts services. Only runs when explicitly called.
96
+ * User-triggered update. Frontend passes the target version.
97
+ * Installs the package, restarts services.
98
+ * Only runs when explicitly called.
99
+ *
100
+ * Body: { "version": "0.4.3" }
144
101
  */
145
102
  updateRouter.post('/', async (c) => {
146
103
  if (updateInProgress) {
147
104
  return c.json({ error: 'Update already in progress' }, 409);
148
105
  }
149
106
 
107
+ const body = await c.req.json().catch(() => ({}));
108
+ const targetVersion = body.version;
109
+
110
+ if (!targetVersion || typeof targetVersion !== 'string') {
111
+ return c.json({ error: 'Missing "version" in request body' }, 400);
112
+ }
113
+
150
114
  updateInProgress = true;
151
115
  try {
152
- const local = await readLocalVersion();
153
- const latestVersion = await fetchLatestVersion();
154
-
155
- if (!latestVersion) {
156
- return c.json({ error: 'Could not reach version service' }, 502);
157
- }
116
+ const currentVersion = await readLocalVersion();
158
117
 
159
- if (local.version === latestVersion) {
118
+ if (currentVersion === targetVersion) {
160
119
  return c.json({
161
120
  upToDate: true,
162
- currentVersion: local.version,
163
- latestVersion,
121
+ currentVersion,
164
122
  });
165
123
  }
166
124
 
167
- console.log(`[Update] User triggered: ${local.version} -> ${latestVersion}`);
168
- const update = await performUpdate(latestVersion);
125
+ console.log(`[Update] User triggered: ${currentVersion} -> ${targetVersion}`);
126
+ const update = await performUpdate(targetVersion);
169
127
 
170
128
  return c.json({
171
129
  success: update.success,
172
- previousVersion: local.version,
173
- currentVersion: update.success ? latestVersion : local.version,
174
- latestVersion,
130
+ previousVersion: currentVersion,
131
+ currentVersion: update.success ? targetVersion : currentVersion,
175
132
  output: update.output,
176
133
  });
177
134
  } catch (e) {
@@ -9,8 +9,8 @@ The Kortix Cron service runs outside the sandbox as a platform service. It manag
9
9
 
10
10
  ## Architecture
11
11
 
12
- - **Service**: `kortix-cron` (Bun + Hono) running at port 8011
13
- - **Database**: `kortix_cron` schema in Supabase PostgreSQL (Drizzle ORM)
12
+ - **Service**: `kortix-api` (Bun + Hono) running at port 8008
13
+ - **Database**: `kortix` schema in Supabase PostgreSQL (Drizzle ORM)
14
14
  - **Scheduler**: Polling loop (1s tick) that checks for due triggers
15
15
  - **Executor**: Calls OpenCode API inside sandbox to create sessions and send prompts
16
16
 
@@ -44,7 +44,7 @@ The Kortix Cron service runs outside the sandbox as a platform service. It manag
44
44
 
45
45
  ## API Reference
46
46
 
47
- Base URL: `http://localhost:8011` (local) or the deployed service URL.
47
+ Base URL: `http://localhost:8008` (local) or the deployed service URL.
48
48
 
49
49
  All `/v1/*` endpoints require `Authorization: Bearer <supabase-jwt>`.
50
50
 
@@ -52,7 +52,7 @@ All `/v1/*` endpoints require `Authorization: Bearer <supabase-jwt>`.
52
52
 
53
53
  ```bash
54
54
  # Register a sandbox
55
- curl -X POST http://localhost:8011/v1/sandboxes \
55
+ curl -X POST http://localhost:8008/v1/sandboxes \
56
56
  -H "Authorization: Bearer $TOKEN" \
57
57
  -H "Content-Type: application/json" \
58
58
  -d '{
@@ -62,11 +62,11 @@ curl -X POST http://localhost:8011/v1/sandboxes \
62
62
  }'
63
63
 
64
64
  # List sandboxes
65
- curl http://localhost:8011/v1/sandboxes \
65
+ curl http://localhost:8008/v1/sandboxes \
66
66
  -H "Authorization: Bearer $TOKEN"
67
67
 
68
68
  # Check sandbox health
69
- curl -X POST http://localhost:8011/v1/sandboxes/{id}/health \
69
+ curl -X POST http://localhost:8008/v1/sandboxes/{id}/health \
70
70
  -H "Authorization: Bearer $TOKEN"
71
71
  ```
72
72
 
@@ -74,7 +74,7 @@ curl -X POST http://localhost:8011/v1/sandboxes/{id}/health \
74
74
 
75
75
  ```bash
76
76
  # Create a trigger - daily report at 9 AM UTC
77
- curl -X POST http://localhost:8011/v1/triggers \
77
+ curl -X POST http://localhost:8008/v1/triggers \
78
78
  -H "Authorization: Bearer $TOKEN" \
79
79
  -H "Content-Type: application/json" \
80
80
  -d '{
@@ -88,7 +88,7 @@ curl -X POST http://localhost:8011/v1/triggers \
88
88
  }'
89
89
 
90
90
  # Create a trigger - every 5 minutes health check
91
- curl -X POST http://localhost:8011/v1/triggers \
91
+ curl -X POST http://localhost:8008/v1/triggers \
92
92
  -H "Authorization: Bearer $TOKEN" \
93
93
  -H "Content-Type: application/json" \
94
94
  -d '{
@@ -101,23 +101,23 @@ curl -X POST http://localhost:8011/v1/triggers \
101
101
  }'
102
102
 
103
103
  # List triggers
104
- curl http://localhost:8011/v1/triggers \
104
+ curl http://localhost:8008/v1/triggers \
105
105
  -H "Authorization: Bearer $TOKEN"
106
106
 
107
107
  # Pause a trigger
108
- curl -X POST http://localhost:8011/v1/triggers/{id}/pause \
108
+ curl -X POST http://localhost:8008/v1/triggers/{id}/pause \
109
109
  -H "Authorization: Bearer $TOKEN"
110
110
 
111
111
  # Resume a trigger
112
- curl -X POST http://localhost:8011/v1/triggers/{id}/resume \
112
+ curl -X POST http://localhost:8008/v1/triggers/{id}/resume \
113
113
  -H "Authorization: Bearer $TOKEN"
114
114
 
115
115
  # Fire a trigger immediately (manual run)
116
- curl -X POST http://localhost:8011/v1/triggers/{id}/run \
116
+ curl -X POST http://localhost:8008/v1/triggers/{id}/run \
117
117
  -H "Authorization: Bearer $TOKEN"
118
118
 
119
119
  # Delete a trigger
120
- curl -X DELETE http://localhost:8011/v1/triggers/{id} \
120
+ curl -X DELETE http://localhost:8008/v1/triggers/{id} \
121
121
  -H "Authorization: Bearer $TOKEN"
122
122
  ```
123
123
 
@@ -125,30 +125,30 @@ curl -X DELETE http://localhost:8011/v1/triggers/{id} \
125
125
 
126
126
  ```bash
127
127
  # List all executions
128
- curl "http://localhost:8011/v1/executions?limit=20" \
128
+ curl "http://localhost:8008/v1/executions?limit=20" \
129
129
  -H "Authorization: Bearer $TOKEN"
130
130
 
131
131
  # Filter by status
132
- curl "http://localhost:8011/v1/executions?status=failed" \
132
+ curl "http://localhost:8008/v1/executions?status=failed" \
133
133
  -H "Authorization: Bearer $TOKEN"
134
134
 
135
135
  # Filter by date range
136
- curl "http://localhost:8011/v1/executions?since=2026-02-01T00:00:00Z&until=2026-02-11T00:00:00Z" \
136
+ curl "http://localhost:8008/v1/executions?since=2026-02-01T00:00:00Z&until=2026-02-11T00:00:00Z" \
137
137
  -H "Authorization: Bearer $TOKEN"
138
138
 
139
139
  # Executions for a specific trigger
140
- curl http://localhost:8011/v1/executions/by-trigger/{triggerId} \
140
+ curl http://localhost:8008/v1/executions/by-trigger/{triggerId} \
141
141
  -H "Authorization: Bearer $TOKEN"
142
142
 
143
143
  # Get execution details
144
- curl http://localhost:8011/v1/executions/{id} \
144
+ curl http://localhost:8008/v1/executions/{id} \
145
145
  -H "Authorization: Bearer $TOKEN"
146
146
  ```
147
147
 
148
148
  ### Health Check (no auth)
149
149
 
150
150
  ```bash
151
- curl http://localhost:8011/health
151
+ curl http://localhost:8008/health
152
152
  # Returns: { status, service, timestamp, scheduler: { running, tickCount, lastTick } }
153
153
  ```
154
154