@lazyingart/agintiflow 0.1.0

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.
@@ -0,0 +1,198 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>AgInTiFlow</title>
7
+ <link rel="icon" type="image/png" href="/logos/logo.png" />
8
+ <link rel="stylesheet" href="/styles.css" />
9
+ </head>
10
+ <body>
11
+ <main class="page">
12
+ <section class="panel form-panel">
13
+ <div class="brand-header">
14
+ <img class="brand-logo" src="/logos/logo.png" alt="AgInTiFlow logo" />
15
+ <div>
16
+ <h1>AgInTiFlow</h1>
17
+ <p class="brand-kicker" data-i18n="brandKicker">AI automation product by AgInTi Inc.</p>
18
+ </div>
19
+ <label class="language-switch">
20
+ <span data-i18n="languageLabel">Language</span>
21
+ <select id="language" name="language" aria-label="Select language">
22
+ <option value="en">English</option>
23
+ <option value="ar">العربية</option>
24
+ <option value="es">Español</option>
25
+ <option value="fr">Français</option>
26
+ <option value="ja">日本語</option>
27
+ <option value="ko">한국어</option>
28
+ <option value="vi">Tiếng Việt</option>
29
+ <option value="zh-Hans">中文 (简体)</option>
30
+ <option value="zh-Hant">繁體中文</option>
31
+ <option value="de">Deutsch</option>
32
+ <option value="ru">Русский</option>
33
+ </select>
34
+ </label>
35
+ </div>
36
+ <p class="subtle" data-i18n="intro">
37
+ Browser agent with provider selection, resumable runs, persisted settings, and an optional guarded shell tool with Docker sandbox support.
38
+ </p>
39
+
40
+ <form id="run-form">
41
+ <label>
42
+ <span data-i18n="routingModeLabel">Routing policy</span>
43
+ <select id="routingMode" name="routingMode">
44
+ <option value="smart" data-i18n="routingSmartOption">Smart: fast unless complex</option>
45
+ <option value="fast" data-i18n="routingFastOption">DeepSeek v4 flash</option>
46
+ <option value="complex" data-i18n="routingComplexOption">DeepSeek v4 pro</option>
47
+ <option value="manual" data-i18n="routingManualOption">Manual provider/model</option>
48
+ </select>
49
+ </label>
50
+
51
+ <div class="grid">
52
+ <label>
53
+ <span data-i18n="providerLabel">Provider</span>
54
+ <select id="provider" name="provider">
55
+ <option value="deepseek">DeepSeek</option>
56
+ <option value="openai">OpenAI</option>
57
+ </select>
58
+ </label>
59
+
60
+ <label>
61
+ <span data-i18n="modelLabel">Model</span>
62
+ <input id="model" name="model" type="text" value="deepseek-v4-flash" />
63
+ </label>
64
+ </div>
65
+
66
+ <p id="routing-hint" class="subtle route-hint"></p>
67
+
68
+ <label>
69
+ <span data-i18n="goalLabel">Goal</span>
70
+ <textarea
71
+ id="goal"
72
+ name="goal"
73
+ rows="5"
74
+ data-i18n-placeholder="goalPlaceholder"
75
+ placeholder="Open a site and summarize it, or use run_command for simple terminal inspection."
76
+ ></textarea>
77
+ </label>
78
+
79
+ <label>
80
+ <span data-i18n="startUrlLabel">Start URL</span>
81
+ <input id="startUrl" name="startUrl" type="url" data-i18n-placeholder="startUrlPlaceholder" placeholder="https://news.ycombinator.com" />
82
+ </label>
83
+
84
+ <label>
85
+ <span data-i18n="allowedDomainsLabel">Allowed domains</span>
86
+ <input id="allowedDomains" name="allowedDomains" type="text" data-i18n-placeholder="allowedDomainsPlaceholder" placeholder="news.ycombinator.com,github.com" />
87
+ </label>
88
+
89
+ <div class="grid">
90
+ <label>
91
+ <span data-i18n="commandCwdLabel">Working directory</span>
92
+ <input id="commandCwd" name="commandCwd" type="text" value="/home/lachlan/ProjectsLFS/Agent" />
93
+ </label>
94
+ <label>
95
+ <span data-i18n="maxStepsLabel">Max steps</span>
96
+ <input id="maxSteps" name="maxSteps" type="number" min="1" max="50" value="15" />
97
+ </label>
98
+ </div>
99
+
100
+ <div class="grid">
101
+ <label>
102
+ <span data-i18n="sandboxModeLabel">Sandbox mode</span>
103
+ <select id="sandboxMode" name="sandboxMode">
104
+ <option value="host" data-i18n="sandboxHostOption">Host read-only</option>
105
+ <option value="docker-readonly" data-i18n="sandboxDockerReadonlyOption">Docker read-only</option>
106
+ <option value="docker-workspace" data-i18n="sandboxDockerWorkspaceOption">Docker workspace-write</option>
107
+ </select>
108
+ </label>
109
+ <label>
110
+ <span data-i18n="packagePolicyLabel">Package installs</span>
111
+ <select id="packageInstallPolicy" name="packageInstallPolicy">
112
+ <option value="block" data-i18n="packageBlockOption">Blocked</option>
113
+ <option value="prompt" data-i18n="packagePromptOption">Require approval</option>
114
+ <option value="allow" data-i18n="packageAllowOption">Approved in Docker</option>
115
+ </select>
116
+ </label>
117
+ </div>
118
+
119
+ <div class="checks">
120
+ <label><input id="headless" name="headless" type="checkbox" checked /> <span data-i18n="headlessLabel">Headless browser</span></label>
121
+ <label><input id="allowShellTool" name="allowShellTool" type="checkbox" checked /> <span data-i18n="shellToolLabel">Enable shell tool</span></label>
122
+ <label><input id="allowWrapperTools" name="allowWrapperTools" type="checkbox" /> <span data-i18n="wrapperToolLabel">Enable agent wrappers</span></label>
123
+ <label><input id="allowPasswords" name="allowPasswords" type="checkbox" /> <span data-i18n="allowPasswordsLabel">Allow password typing</span></label>
124
+ <label><input id="allowDestructive" name="allowDestructive" type="checkbox" /> <span data-i18n="allowDestructiveLabel">Allow destructive actions</span></label>
125
+ </div>
126
+
127
+ <label>
128
+ <span data-i18n="dockerImageLabel">Docker image</span>
129
+ <input
130
+ id="dockerSandboxImage"
131
+ name="dockerSandboxImage"
132
+ type="text"
133
+ value="agintiflow-sandbox:latest"
134
+ data-i18n-placeholder="dockerImagePlaceholder"
135
+ placeholder="agintiflow-sandbox:latest"
136
+ />
137
+ </label>
138
+
139
+ <div class="actions">
140
+ <button type="submit" data-i18n="startRunButton">Start run</button>
141
+ <span id="key-status" class="subtle"></span>
142
+ </div>
143
+ <p id="wrapper-status" class="subtle wrapper-status"></p>
144
+
145
+ <section class="sandbox-card">
146
+ <div class="header-row">
147
+ <div>
148
+ <h2 data-i18n="sandboxStatusTitle">Sandbox status</h2>
149
+ <p id="sandbox-status" class="subtle route-hint" data-i18n="sandboxStatusEmpty">Not checked yet.</p>
150
+ </div>
151
+ <div class="sandbox-actions">
152
+ <button id="check-sandbox" type="button" class="secondary" data-i18n="checkSandboxButton">Check</button>
153
+ <button id="preflight-sandbox" type="button" class="secondary" data-i18n="preflightSandboxButton">Preflight</button>
154
+ </div>
155
+ </div>
156
+ <pre id="sandbox-logs" class="sandbox-logs" data-i18n="sandboxLogsEmpty">No sandbox logs yet.</pre>
157
+ </section>
158
+ </form>
159
+ </section>
160
+
161
+ <section class="stack">
162
+ <section class="panel output-panel">
163
+ <div class="header-row">
164
+ <h2 data-i18n="runOutputTitle">Run output</h2>
165
+ <div id="run-meta" class="subtle"></div>
166
+ </div>
167
+ <pre id="logs" class="logs" data-i18n="noRunStarted">No run started.</pre>
168
+ </section>
169
+
170
+ <section class="panel chat-panel">
171
+ <div class="header-row">
172
+ <h2 data-i18n="conversationTitle">Conversation</h2>
173
+ <select id="session-select" class="session-select">
174
+ <option value="" data-i18n="noSessionSelected">No session selected</option>
175
+ </select>
176
+ </div>
177
+ <div id="chat-thread" class="chat-thread">
178
+ <div class="subtle" data-i18n="noConversationLoaded">No conversation loaded.</div>
179
+ </div>
180
+ <form id="chat-form" class="chat-form">
181
+ <textarea
182
+ id="chat-input"
183
+ rows="4"
184
+ data-i18n-placeholder="chatPlaceholder"
185
+ placeholder="Continue the selected conversation here."
186
+ ></textarea>
187
+ <div class="actions">
188
+ <button type="submit" data-i18n="sendMessageButton">Send message</button>
189
+ <span id="chat-status" class="subtle"></span>
190
+ </div>
191
+ </form>
192
+ </section>
193
+ </section>
194
+ </main>
195
+
196
+ <script src="/app.js" type="module"></script>
197
+ </body>
198
+ </html>
@@ -0,0 +1,305 @@
1
+ :root {
2
+ color-scheme: light;
3
+ --bg: #f4efe6;
4
+ --panel: rgba(255, 251, 244, 0.92);
5
+ --ink: #1d1c1a;
6
+ --muted: #5f564a;
7
+ --line: #d9cdbb;
8
+ --accent: #0f766e;
9
+ --assistant: #f3ede2;
10
+ --user: #dff4f0;
11
+ }
12
+
13
+ * {
14
+ box-sizing: border-box;
15
+ }
16
+
17
+ body {
18
+ margin: 0;
19
+ font-family: "IBM Plex Sans", "Segoe UI", sans-serif;
20
+ color: var(--ink);
21
+ background:
22
+ radial-gradient(circle at top left, rgba(217, 119, 6, 0.14), transparent 30%),
23
+ radial-gradient(circle at top right, rgba(15, 118, 110, 0.12), transparent 28%),
24
+ linear-gradient(180deg, #f8f3eb, var(--bg));
25
+ }
26
+
27
+ .page {
28
+ width: min(1240px, calc(100% - 32px));
29
+ margin: 32px auto;
30
+ display: grid;
31
+ gap: 20px;
32
+ grid-template-columns: minmax(320px, 420px) minmax(0, 1fr);
33
+ }
34
+
35
+ .stack {
36
+ display: grid;
37
+ gap: 20px;
38
+ }
39
+
40
+ .panel {
41
+ background: var(--panel);
42
+ border: 1px solid var(--line);
43
+ border-radius: 18px;
44
+ padding: 20px;
45
+ box-shadow: 0 18px 50px rgba(62, 49, 26, 0.08);
46
+ }
47
+
48
+ h1,
49
+ h2 {
50
+ margin-top: 0;
51
+ font-family: "IBM Plex Serif", "Georgia", serif;
52
+ }
53
+
54
+ h1 {
55
+ margin-bottom: 4px;
56
+ }
57
+
58
+ .brand-header {
59
+ display: grid;
60
+ grid-template-columns: 92px minmax(0, 1fr);
61
+ gap: 16px;
62
+ align-items: center;
63
+ margin-bottom: 14px;
64
+ }
65
+
66
+ .brand-logo {
67
+ width: 92px;
68
+ aspect-ratio: 1;
69
+ object-fit: contain;
70
+ filter: drop-shadow(0 14px 28px rgba(15, 118, 110, 0.18));
71
+ }
72
+
73
+ .brand-kicker {
74
+ margin: 0;
75
+ color: var(--muted);
76
+ font-size: 0.82rem;
77
+ font-weight: 700;
78
+ letter-spacing: 0.08em;
79
+ text-transform: uppercase;
80
+ }
81
+
82
+ .language-switch {
83
+ grid-column: 1 / -1;
84
+ display: grid;
85
+ grid-template-columns: auto minmax(0, 1fr);
86
+ gap: 10px;
87
+ align-items: center;
88
+ margin-top: 2px;
89
+ }
90
+
91
+ .language-switch span {
92
+ color: var(--muted);
93
+ font-size: 0.76rem;
94
+ font-weight: 800;
95
+ letter-spacing: 0.08em;
96
+ text-transform: uppercase;
97
+ }
98
+
99
+ .subtle {
100
+ color: var(--muted);
101
+ }
102
+
103
+ .route-hint,
104
+ .wrapper-status {
105
+ margin: -4px 0 0;
106
+ font-size: 0.88rem;
107
+ line-height: 1.45;
108
+ }
109
+
110
+ form,
111
+ .checks {
112
+ display: grid;
113
+ gap: 14px;
114
+ }
115
+
116
+ .grid {
117
+ display: grid;
118
+ gap: 14px;
119
+ grid-template-columns: 1fr 140px;
120
+ }
121
+
122
+ label {
123
+ display: grid;
124
+ gap: 6px;
125
+ font-size: 0.95rem;
126
+ }
127
+
128
+ input,
129
+ textarea,
130
+ select,
131
+ button {
132
+ font: inherit;
133
+ }
134
+
135
+ input,
136
+ textarea,
137
+ select {
138
+ width: 100%;
139
+ border: 1px solid var(--line);
140
+ background: #fffdfa;
141
+ color: var(--ink);
142
+ border-radius: 12px;
143
+ padding: 11px 12px;
144
+ }
145
+
146
+ textarea {
147
+ resize: vertical;
148
+ }
149
+
150
+ .checks {
151
+ grid-template-columns: repeat(2, minmax(0, 1fr));
152
+ }
153
+
154
+ .checks label {
155
+ align-items: center;
156
+ grid-auto-flow: column;
157
+ justify-content: start;
158
+ gap: 10px;
159
+ }
160
+
161
+ button {
162
+ border: 0;
163
+ border-radius: 999px;
164
+ padding: 11px 18px;
165
+ background: linear-gradient(135deg, var(--accent), #155e75);
166
+ color: white;
167
+ font-weight: 600;
168
+ cursor: pointer;
169
+ }
170
+
171
+ button.secondary {
172
+ border: 1px solid var(--line);
173
+ background: #fffdfa;
174
+ color: var(--ink);
175
+ }
176
+
177
+ .actions,
178
+ .header-row {
179
+ display: flex;
180
+ gap: 12px;
181
+ align-items: center;
182
+ justify-content: space-between;
183
+ }
184
+
185
+ .sandbox-card {
186
+ display: grid;
187
+ gap: 12px;
188
+ margin-top: 4px;
189
+ padding: 14px;
190
+ border: 1px solid rgba(15, 118, 110, 0.18);
191
+ border-radius: 16px;
192
+ background: rgba(255, 253, 250, 0.7);
193
+ }
194
+
195
+ .sandbox-card h2 {
196
+ margin: 0 0 4px;
197
+ font-size: 1.05rem;
198
+ }
199
+
200
+ .sandbox-actions {
201
+ display: flex;
202
+ flex-wrap: wrap;
203
+ gap: 8px;
204
+ }
205
+
206
+ .sandbox-logs {
207
+ min-height: 96px;
208
+ max-height: 220px;
209
+ overflow: auto;
210
+ margin: 0;
211
+ padding: 12px;
212
+ border-radius: 12px;
213
+ background: #0f172a;
214
+ color: #dbeafe;
215
+ border: 1px solid #1e293b;
216
+ font-family: "IBM Plex Mono", "SFMono-Regular", monospace;
217
+ font-size: 0.78rem;
218
+ line-height: 1.45;
219
+ white-space: pre-wrap;
220
+ }
221
+
222
+ .session-select {
223
+ max-width: 340px;
224
+ }
225
+
226
+ .logs {
227
+ min-height: 360px;
228
+ max-height: 48vh;
229
+ overflow: auto;
230
+ margin: 0;
231
+ padding: 16px;
232
+ border-radius: 14px;
233
+ background: #151515;
234
+ color: #dfdfd8;
235
+ border: 1px solid #2d2d2d;
236
+ font-family: "IBM Plex Mono", "SFMono-Regular", monospace;
237
+ font-size: 0.9rem;
238
+ line-height: 1.5;
239
+ white-space: pre-wrap;
240
+ }
241
+
242
+ .chat-thread {
243
+ min-height: 260px;
244
+ max-height: 40vh;
245
+ overflow: auto;
246
+ display: grid;
247
+ gap: 12px;
248
+ padding: 6px 2px;
249
+ }
250
+
251
+ .chat-item {
252
+ border: 1px solid var(--line);
253
+ border-radius: 14px;
254
+ padding: 12px 14px;
255
+ }
256
+
257
+ .chat-item.user {
258
+ background: var(--user);
259
+ }
260
+
261
+ .chat-item.assistant {
262
+ background: var(--assistant);
263
+ }
264
+
265
+ .chat-meta {
266
+ font-size: 0.8rem;
267
+ color: var(--muted);
268
+ margin-bottom: 8px;
269
+ }
270
+
271
+ .chat-content {
272
+ line-height: 1.5;
273
+ }
274
+
275
+ .chat-form {
276
+ margin-top: 14px;
277
+ }
278
+
279
+ @media (max-width: 960px) {
280
+ .page {
281
+ grid-template-columns: 1fr;
282
+ }
283
+
284
+ .brand-header {
285
+ grid-template-columns: 76px 1fr;
286
+ }
287
+
288
+ .brand-logo {
289
+ width: 76px;
290
+ }
291
+
292
+ .language-switch {
293
+ grid-column: 1 / -1;
294
+ grid-template-columns: 1fr;
295
+ }
296
+
297
+ .logs {
298
+ min-height: 320px;
299
+ max-height: 44vh;
300
+ }
301
+
302
+ .chat-thread {
303
+ max-height: 34vh;
304
+ }
305
+ }
package/run.js ADDED
@@ -0,0 +1,6 @@
1
+ import { main } from "./src/cli.js";
2
+
3
+ main().catch((error) => {
4
+ console.error(error);
5
+ process.exit(1);
6
+ });
@@ -0,0 +1,140 @@
1
+ #!/usr/bin/env bash
2
+ set -Eeuo pipefail
3
+
4
+ if [[ ! -r /etc/os-release ]]; then
5
+ echo "This script requires /etc/os-release." >&2
6
+ exit 1
7
+ fi
8
+
9
+ . /etc/os-release
10
+
11
+ if [[ "${ID:-}" != "ubuntu" ]]; then
12
+ echo "This script targets Ubuntu hosts. Detected ID=${ID:-unknown}." >&2
13
+ exit 1
14
+ fi
15
+
16
+ if ! command -v apt-get >/dev/null 2>&1; then
17
+ echo "apt-get is required on this host." >&2
18
+ exit 1
19
+ fi
20
+
21
+ if ! command -v dpkg >/dev/null 2>&1; then
22
+ echo "dpkg is required on this host." >&2
23
+ exit 1
24
+ fi
25
+
26
+ if [[ "${EUID}" -eq 0 ]]; then
27
+ SUDO=()
28
+ else
29
+ if ! command -v sudo >/dev/null 2>&1; then
30
+ echo "Run this script as root or install sudo first." >&2
31
+ exit 1
32
+ fi
33
+ SUDO=(sudo)
34
+ fi
35
+
36
+ TARGET_USER="${DOCKER_TARGET_USER:-${SUDO_USER:-}}"
37
+ ARCHITECTURE="$(dpkg --print-architecture)"
38
+ CODENAME="${UBUNTU_CODENAME:-${VERSION_CODENAME:-}}"
39
+
40
+ if [[ -z "${CODENAME}" ]]; then
41
+ echo "Unable to determine the Ubuntu codename." >&2
42
+ exit 1
43
+ fi
44
+
45
+ CONFLICTING_PACKAGES=(
46
+ docker.io
47
+ docker-compose
48
+ docker-compose-v2
49
+ docker-doc
50
+ podman-docker
51
+ containerd
52
+ runc
53
+ )
54
+
55
+ DOCKER_PACKAGES=(
56
+ docker-ce
57
+ docker-ce-cli
58
+ containerd.io
59
+ docker-buildx-plugin
60
+ docker-compose-plugin
61
+ )
62
+
63
+ run() {
64
+ echo "+ $*"
65
+ "$@"
66
+ }
67
+
68
+ echo "Installing Docker Engine for Ubuntu ${VERSION_ID:-unknown} (${CODENAME}) on ${ARCHITECTURE}."
69
+
70
+ mapfile -t INSTALLED_CONFLICTS < <(
71
+ dpkg-query -W -f='${db:Status-Abbrev} ${binary:Package}\n' "${CONFLICTING_PACKAGES[@]}" 2>/dev/null |
72
+ awk '$1 ~ /^ii/ { print $2 }'
73
+ )
74
+ if [[ "${#INSTALLED_CONFLICTS[@]}" -gt 0 ]]; then
75
+ run "${SUDO[@]}" apt-get remove -y "${INSTALLED_CONFLICTS[@]}"
76
+ fi
77
+
78
+ run "${SUDO[@]}" apt-get update
79
+ run "${SUDO[@]}" apt-get install -y ca-certificates curl
80
+ run "${SUDO[@]}" install -m 0755 -d /etc/apt/keyrings
81
+ run "${SUDO[@]}" curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
82
+ run "${SUDO[@]}" chmod a+r /etc/apt/keyrings/docker.asc
83
+
84
+ DOCKER_SOURCE_FILE="/etc/apt/sources.list.d/docker.sources"
85
+ DOCKER_SOURCE_CONTENT="$(cat <<EOF
86
+ Types: deb
87
+ URIs: https://download.docker.com/linux/ubuntu
88
+ Suites: ${CODENAME}
89
+ Components: stable
90
+ Architectures: ${ARCHITECTURE}
91
+ Signed-By: /etc/apt/keyrings/docker.asc
92
+ EOF
93
+ )"
94
+
95
+ echo "+ writing ${DOCKER_SOURCE_FILE}"
96
+ printf '%s\n' "${DOCKER_SOURCE_CONTENT}" | "${SUDO[@]}" tee "${DOCKER_SOURCE_FILE}" >/dev/null
97
+
98
+ run "${SUDO[@]}" apt-get update
99
+ run "${SUDO[@]}" apt-get install -y "${DOCKER_PACKAGES[@]}"
100
+
101
+ if command -v systemctl >/dev/null 2>&1; then
102
+ run "${SUDO[@]}" systemctl enable --now containerd
103
+ run "${SUDO[@]}" systemctl enable --now docker
104
+ fi
105
+
106
+ if [[ -n "${TARGET_USER}" && "${TARGET_USER}" != "root" ]]; then
107
+ if ! getent group docker >/dev/null 2>&1; then
108
+ run "${SUDO[@]}" groupadd docker
109
+ fi
110
+ run "${SUDO[@]}" usermod -aG docker "${TARGET_USER}"
111
+ fi
112
+
113
+ run "${SUDO[@]}" docker version
114
+
115
+ if [[ "${RUN_HELLO_WORLD:-1}" == "1" ]]; then
116
+ run "${SUDO[@]}" docker run --rm hello-world
117
+ fi
118
+
119
+ if [[ -n "${TARGET_USER}" && "${TARGET_USER}" != "root" ]]; then
120
+ run "${SUDO[@]}" -u "${TARGET_USER}" sg docker -c "docker version >/dev/null"
121
+ fi
122
+
123
+ echo
124
+ echo "Docker installation is complete."
125
+ echo "CLI checks:"
126
+ echo " docker --version"
127
+ echo " docker compose version"
128
+ echo
129
+ if [[ -n "${TARGET_USER}" && "${TARGET_USER}" != "root" ]]; then
130
+ echo "The user '${TARGET_USER}' was added to the docker group."
131
+ echo "Open a new login shell, sign out and back in, or run:"
132
+ echo " newgrp docker"
133
+ echo
134
+ echo "After group refresh, verify non-root access with:"
135
+ echo " docker run --rm hello-world"
136
+ else
137
+ echo "No non-root target user was configured."
138
+ echo "If you ran this as root and want a regular user to access Docker, rerun with:"
139
+ echo " DOCKER_TARGET_USER=<your-username> ./scripts/install-docker-ubuntu.sh"
140
+ fi