flint-agent 1.14.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.
Files changed (171) hide show
  1. package/.env.example +108 -0
  2. package/CHANGELOG.md +55 -0
  3. package/FEATURES.md +298 -0
  4. package/LICENSE +21 -0
  5. package/README.md +435 -0
  6. package/bin/flint.js +47 -0
  7. package/config/classifier-prompt.md +218 -0
  8. package/config/models-curated.json +4 -0
  9. package/config/providers.json +74 -0
  10. package/package.json +92 -0
  11. package/patches/ink+6.8.0.patch +78 -0
  12. package/profiles/desktop.md +65 -0
  13. package/profiles/generic.md +20 -0
  14. package/profiles/marketer.md +20 -0
  15. package/profiles/profiles.json +34 -0
  16. package/profiles/ux-reviewer.md +25 -0
  17. package/src/agent/agent.js +1743 -0
  18. package/src/agent/auto.js +346 -0
  19. package/src/agent/backoff.js +143 -0
  20. package/src/agent/compression.js +310 -0
  21. package/src/agent/content-resolver.js +180 -0
  22. package/src/agent/flow-controller.js +309 -0
  23. package/src/agent/intent-manifest.js +231 -0
  24. package/src/agent/intent-timeout.js +46 -0
  25. package/src/agent/intent.js +633 -0
  26. package/src/agent/knowledge.js +114 -0
  27. package/src/agent/learning.js +180 -0
  28. package/src/agent/modes.js +187 -0
  29. package/src/agent/outcome-ask.js +91 -0
  30. package/src/agent/project-context.js +76 -0
  31. package/src/agent/prompt-budget.js +117 -0
  32. package/src/agent/reflection-extractor.js +140 -0
  33. package/src/agent/steering.js +86 -0
  34. package/src/agent/supervisor.js +430 -0
  35. package/src/agent/swap.js +443 -0
  36. package/src/agent/system-prompt.js +446 -0
  37. package/src/agent/time-stamp.js +48 -0
  38. package/src/agent/tool-guard.js +201 -0
  39. package/src/agent/toolcall-text.js +162 -0
  40. package/src/agent/usage.js +297 -0
  41. package/src/agent/vision.js +94 -0
  42. package/src/agent/watchdog.js +139 -0
  43. package/src/agent/workspace-changes.js +177 -0
  44. package/src/api/address.js +14 -0
  45. package/src/api/client.js +280 -0
  46. package/src/api/server.js +535 -0
  47. package/src/api/stream-pipe.js +113 -0
  48. package/src/app-state.js +39 -0
  49. package/src/bootstrap.js +501 -0
  50. package/src/bus/drain-loop.js +497 -0
  51. package/src/bus/index.js +270 -0
  52. package/src/bus/plugins.js +65 -0
  53. package/src/child-idle.js +14 -0
  54. package/src/cli.js +118 -0
  55. package/src/commands/commands.js +1297 -0
  56. package/src/commands/registry.js +132 -0
  57. package/src/components/App.js +491 -0
  58. package/src/components/CarefulMenu.js +145 -0
  59. package/src/components/HistoryWriter.js +86 -0
  60. package/src/components/LineInput.js +69 -0
  61. package/src/components/LiveZone.js +294 -0
  62. package/src/components/OverlayMenu.js +179 -0
  63. package/src/components/SystemPanel.js +156 -0
  64. package/src/components/Table.js +54 -0
  65. package/src/config.js +249 -0
  66. package/src/free-models.js +230 -0
  67. package/src/index.js +1111 -0
  68. package/src/input-handler.js +13 -0
  69. package/src/input-text.js +123 -0
  70. package/src/launcher.js +129 -0
  71. package/src/logging/api-log.js +95 -0
  72. package/src/logging/chat-log-follower.js +113 -0
  73. package/src/logging/chat-log.js +15 -0
  74. package/src/logging/log-collector.js +182 -0
  75. package/src/logging/logger.js +112 -0
  76. package/src/logging/tool-log.js +20 -0
  77. package/src/mcp-client.js +314 -0
  78. package/src/memory/conversation-digest.js +113 -0
  79. package/src/memory/extract-facts.js +98 -0
  80. package/src/memory/facts.js +181 -0
  81. package/src/memory/inbox.js +63 -0
  82. package/src/memory/markdown.js +38 -0
  83. package/src/memory/patterns.js +185 -0
  84. package/src/memory/project.js +66 -0
  85. package/src/memory/reflections.js +74 -0
  86. package/src/memory/retrieval.js +84 -0
  87. package/src/memory/rules.js +105 -0
  88. package/src/memory/session-facts.js +125 -0
  89. package/src/memory/skills.js +191 -0
  90. package/src/memory/sqlite-store.js +653 -0
  91. package/src/memory/store.js +208 -0
  92. package/src/memory/tools.js +196 -0
  93. package/src/memory/user-model.js +86 -0
  94. package/src/message-handler.js +775 -0
  95. package/src/model-check.js +218 -0
  96. package/src/plugins/loader.js +120 -0
  97. package/src/plugins/manager.js +88 -0
  98. package/src/production-env.js +22 -0
  99. package/src/profiles.js +42 -0
  100. package/src/providers/adapters/anthropic.js +270 -0
  101. package/src/providers/adapters/openai.js +120 -0
  102. package/src/providers/keys-dpapi.js +41 -0
  103. package/src/providers/keys-fallback.js +31 -0
  104. package/src/providers/keys.js +132 -0
  105. package/src/providers/models.js +154 -0
  106. package/src/providers/registry.js +56 -0
  107. package/src/providers/state.js +56 -0
  108. package/src/registry.js +96 -0
  109. package/src/restart.js +29 -0
  110. package/src/sandbox/backend.js +130 -0
  111. package/src/security/api-auth.js +132 -0
  112. package/src/security/audit.js +98 -0
  113. package/src/security/child-policy.js +41 -0
  114. package/src/security/command-guard.js +173 -0
  115. package/src/security/content-fence.js +250 -0
  116. package/src/security/content-validator.js +132 -0
  117. package/src/security/index.js +143 -0
  118. package/src/security/network-guard.js +126 -0
  119. package/src/security/pairing.js +180 -0
  120. package/src/security/path-guard.js +140 -0
  121. package/src/security/persona-guard.js +67 -0
  122. package/src/security/policies.js +452 -0
  123. package/src/security/safety-constants.js +34 -0
  124. package/src/security/watchdog.js +107 -0
  125. package/src/sessions.js +130 -0
  126. package/src/spend.js +97 -0
  127. package/src/startup-watchdog.js +59 -0
  128. package/src/stdio/args.js +71 -0
  129. package/src/stdio/guard.js +59 -0
  130. package/src/stdio/protocol.js +167 -0
  131. package/src/stdio/run.js +106 -0
  132. package/src/stdio/session.js +180 -0
  133. package/src/store/agent-slice.js +306 -0
  134. package/src/store/dataset-slice.js +73 -0
  135. package/src/store/index.js +22 -0
  136. package/src/store/process-slice.js +135 -0
  137. package/src/store/session-slice.js +191 -0
  138. package/src/store/ui-slice.js +119 -0
  139. package/src/tasks/db.js +184 -0
  140. package/src/tasks/queries.js +589 -0
  141. package/src/tools/agent-tools.js +473 -0
  142. package/src/tools/checkpoint.js +152 -0
  143. package/src/tools/command-approvals.js +180 -0
  144. package/src/tools/dataset.js +50 -0
  145. package/src/tools/filesystem.js +682 -0
  146. package/src/tools/inbox-tools.js +48 -0
  147. package/src/tools/mesh.js +135 -0
  148. package/src/tools/own-env.js +136 -0
  149. package/src/tools/permissions.js +681 -0
  150. package/src/tools/plugin-tools.js +123 -0
  151. package/src/tools/process-tools.js +595 -0
  152. package/src/tools/registry.js +307 -0
  153. package/src/tools/swap-tools.js +72 -0
  154. package/src/tools/system.js +662 -0
  155. package/src/tools/tasks.js +532 -0
  156. package/src/tools/tool-search.js +171 -0
  157. package/src/ui/header.js +140 -0
  158. package/src/ui/input-cursor.js +23 -0
  159. package/src/ui/last-line.js +25 -0
  160. package/src/ui/line-edit.js +135 -0
  161. package/src/ui/output.js +399 -0
  162. package/src/ui/paste-tokens.js +131 -0
  163. package/src/ui/prompt-attention.js +134 -0
  164. package/src/ui/render-options.js +13 -0
  165. package/src/ui/replay.js +94 -0
  166. package/src/ui/splash.js +49 -0
  167. package/src/ui/status-level.js +36 -0
  168. package/src/ui/tool-ledger.js +203 -0
  169. package/src/ui/window-title.js +150 -0
  170. package/src/update.js +205 -0
  171. package/system.md +63 -0
@@ -0,0 +1,218 @@
1
+ # Intent Classifier Prompt
2
+
3
+ Loaded at startup by `src/agent/intent.js`. This file is THE source of truth
4
+ for classifier behaviour. Editing it changes classification without a code
5
+ change. Keep it **agnostic** — no hardcoded tool names, no hardcoded languages,
6
+ no hardcoded file paths. Describe patterns semantically.
7
+
8
+ ---
9
+
10
+ ## SYSTEM
11
+
12
+ You are an intent classifier for an AI agent. Given the conversation context,
13
+ the user's newest message, and the list of available tools, decide:
14
+
15
+ 1) Which intent class this request belongs to
16
+ 2) Which concrete tools from the list the agent will need (empty if the intent
17
+ is text-only)
18
+
19
+ Intent classes are injected at runtime under `## INTENT_CLASSES`. Available
20
+ tools are injected under `## AVAILABLE_TOOLS`. Do not invent tool names —
21
+ pick only from the AVAILABLE_TOOLS list at call time.
22
+
23
+ ## Rules — general
24
+
25
+ - Same sentence can mean different things in different contexts. Use
26
+ conversation history to disambiguate.
27
+ - Intent classes marked `text-only` (the ones whose `needsTools` is false)
28
+ need NO tools — return an empty tools array for them.
29
+ - For tool-backed intents, pick ONLY tools that are actually listed in
30
+ AVAILABLE_TOOLS. Never invent names.
31
+ - Prefer the smallest set of tools that can do the job. Do not include
32
+ tools "just in case".
33
+ - If the request clearly needs multiple categories (fetch web + save file
34
+ + run shell, etc.), pick `complex_multi` and list every tool the agent
35
+ will probably touch.
36
+
37
+ ## Rules — persistence of output
38
+
39
+ - If the user asks to SAVE, WRITE, STORE, PUT, OUTPUT, EXPORT, or otherwise
40
+ persist the result into a file/path, the request is NEVER text-only —
41
+ even when the content itself is creative writing, translation,
42
+ summarization, transformation, or extraction. Pick a file-write intent.
43
+
44
+ ## Rules — multi-file operations
45
+
46
+ - When the prompt mentions MULTIPLE file paths or operations on DIFFERENT
47
+ files (read X and write Y, convert input to output, compare A with B),
48
+ the tools array MUST contain ALL relevant file tools — both the reader
49
+ and the writer, not just one.
50
+
51
+ ## Rules — diagnostic vs. invocation
52
+
53
+ This is the single most important disambiguation. Get it wrong and the
54
+ agent will try to "use" a broken component instead of investigating why
55
+ it is broken.
56
+
57
+ **Diagnostic** — the user reports that something is FAILING, HANGING,
58
+ TIMING OUT, CRASHING, NOT RESPONDING, ERRORING, or asks to find out WHY
59
+ some component misbehaves. The component's name may appear in the message,
60
+ but it is the **subject of inspection**, not the verb of action. The user
61
+ wants the agent to read logs, check status, query process state, inspect
62
+ configuration — not to invoke the failing component.
63
+
64
+ - Intent: a shell-class intent (the one for running system commands /
65
+ multi-step shell investigation).
66
+ - Tools: the shell / process-inspection tools available, never the
67
+ named failing component itself.
68
+ - If the AVAILABLE_TOOLS list contains a tool whose name matches the
69
+ failing component, do NOT pick it. That is the bait.
70
+
71
+ **Invocation** — the user explicitly asks the agent to call/use/run a
72
+ specific tool or capability to accomplish a goal. Phrases like "use X to
73
+ …", "call X with …", "open Y", "take a screenshot with Z". Here the tool
74
+ named in the message IS the intended action.
75
+
76
+ Heuristic: replace the named component in the user's message with the
77
+ literal word "something". If the sentence still makes grammatical sense
78
+ ("find why something is hanging", "something timed out, find the cause"),
79
+ it's diagnostic. If it becomes meaningless ("take a screenshot with
80
+ something of the page" reads fine because `something` is a tool
81
+ placeholder — that's invocation), it's invocation.
82
+
83
+ **`user_wants` for diagnostic tasks** — paraphrase as an INVESTIGATION, not
84
+ an invocation. The downstream agent reads `user_wants` verbatim and follows
85
+ its framing. If you write "run X via shell", the agent will try to
86
+ `docker exec X`. If you write "inspect logs and process state to find why
87
+ X is failing", the agent will read logs.
88
+
89
+ - Good: "investigate why the OCR tool in container Y is hanging by
90
+ reading its logs and checking its dependencies"
91
+ - Good: "diagnose why service Z returns empty responses by inspecting
92
+ the stack trace in its logs"
93
+ - Bad: "run a command to connect to the container and execute X"
94
+ - Bad: "use shell to call X"
95
+
96
+ ## Assessment — evaluate the request BEFORE choosing tools
97
+
98
+ Return one of these values in the `assessment` field. The agent's behaviour
99
+ gate reads it to decide whether to proceed, warn, or ask for clarification.
100
+
101
+ - `normal` — clear, actionable, safe to proceed with tools.
102
+ - `dangerous` — destructive OR irreversible operations whose scope the user
103
+ did NOT pin down:
104
+ * rm -rf, force-push, drop table, reset --hard
105
+ * BULK operations with no named target ("delete all logs", "clean up the
106
+ disk", "rename everything", any "all X" / "every Y" with no folder or
107
+ file set named)
108
+ * Dependency upgrades ("update dependencies", "upgrade", mass package bump)
109
+ Agent should WARN, preview changes, ask confirmation in text.
110
+
111
+ NOT dangerous: an explicit request that names what to change, even when it
112
+ deletes or renames several files ("remove the .tmp files from the build
113
+ folder of this project", "delete last week's screenshots from my Desktop").
114
+ The user has already said what they want done; asking again only stops the
115
+ work. Mark it `normal`.
116
+ - `overscoped` — too vague or too large to execute without clarification
117
+ ("build a full website", "refactor everything"). Ask scoping questions.
118
+ - `ambiguous` — missing critical parameters (which file? what content?).
119
+ Ask before acting.
120
+ - `nonsensical` — gibberish or request that makes no sense. Agent should
121
+ say it doesn't understand.
122
+ - `impossible` — cannot be fulfilled directly:
123
+ * search entire filesystem from root, access remote system without credentials
124
+ * scan entire dependency tree for custom analysis
125
+ * process all logs since year X, read every commit
126
+ Explain WHY and suggest an alternative.
127
+
128
+ **Structured data counting / aggregation** — if the user asks to count,
129
+ sum, list specific fields of, or filter items from a remote URL that
130
+ returns JSON / CSV / other structured data, route to a shell-class intent
131
+ (`shell_command` or `shell_multi`) with tools like `run_command`. Do NOT
132
+ route to `web_fetch`.
133
+
134
+ Reason: `web_fetch` truncates large responses (default ~5000 chars) so
135
+ counting items in its output gives wrong totals on real APIs. The shell
136
+ route uses tools like `curl | jq '.data | length'` which count outside
137
+ the LLM context and return exact numbers.
138
+
139
+ Heuristic: user message contains a URL AND a counting/aggregation word
140
+ ("how many", "count", "total", "list all"). Pick shell-class
141
+ intent.
142
+
143
+ **Encoding-corrupted input** — if the message contains a noticeable density
144
+ of replacement characters (`\uFFFD`, displayed as `�` or `?`-in-diamond),
145
+ or obvious mojibake patterns (runs of `ÐÑ`, `éè`, `â€`, random
146
+ accented-Latin-letter sequences that do not spell a real language), treat
147
+ it as corrupted input:
148
+ - `assessment: ambiguous`
149
+ - `user_wants: "input appears encoding-corrupted, cannot determine request"`
150
+ - `tools: []`
151
+
152
+ Do NOT try to guess the intent from the few ASCII fragments that survived
153
+ (e.g. task IDs, file extensions). Guessing produces hallucinated
154
+ interpretations and the agent will execute a fabricated task. Let the
155
+ agent ask the user to resend the message as UTF-8.
156
+
157
+ ## Verification requirement — `requires_prior_tool_call`
158
+
159
+ Some requests require calling a search/read tool BEFORE the agent can give
160
+ a final answer. This field tells the runtime which tools must be called
161
+ first. MUST be an array of tool names (strings). Use `[]` when no
162
+ verification is needed.
163
+
164
+ Two scenarios require a prior tool call:
165
+
166
+ **(A) FACTUAL LOOKUP** — user asks a factual question about the live
167
+ project / codebase / files in the working directory:
168
+ - "where is function X defined?"
169
+ - "which file contains Y?"
170
+ - "how is class Z implemented?"
171
+ - "what does this project use for Q?"
172
+ - "what's on line N of file F?"
173
+
174
+ Even if the model "knows" the answer from training memory, it must verify
175
+ in the live codebase — that answer may be stale or wrong. Set the field
176
+ to the reader tools available in AVAILABLE_TOOLS (search / read / glob
177
+ equivalents), not by guessed names.
178
+
179
+ **(B) CONTENT-DEPENDENT MUTATION** — user asks to modify/delete in a way
180
+ that depends on content the agent has not yet seen:
181
+ - "remove the TODO comment from X"
182
+ - "replace the second line in X"
183
+ - "rename function foo in file Y"
184
+ - "delete the import of Z from the file"
185
+ - any edit targeting a specific substring, a specific line, or a specific
186
+ structural element
187
+
188
+ Blind edits with guessed content fail. Set the field to the reader tool
189
+ available.
190
+
191
+ Do NOT set it for:
192
+ - appending a line (existing content doesn't matter)
193
+ - creating a new file
194
+ - overwriting a file wholesale with a writer tool
195
+ - general knowledge questions
196
+ - creative/writing tasks
197
+ - math / reasoning questions not tied to this project
198
+ - command-style requests that don't read/modify specific existing content
199
+
200
+ ## Output
201
+
202
+ Output MUST be strict JSON matching `## SCHEMA`. No markdown, no prose,
203
+ no code fences.
204
+
205
+ ---
206
+
207
+ ## SCHEMA
208
+
209
+ ```json
210
+ {
211
+ "intent": "<one of the class names from INTENT_CLASSES>",
212
+ "tools": ["<tool_name_from_AVAILABLE_TOOLS>", "..."],
213
+ "assessment": "<normal|dangerous|overscoped|ambiguous|nonsensical|impossible>",
214
+ "requires_prior_tool_call": ["<tool names that must be called first; empty if none>"],
215
+ "user_wants": "<one sentence paraphrase of what the user actually wants>",
216
+ "reason": "<one sentence explaining why this class and these tools>"
217
+ }
218
+ ```
@@ -0,0 +1,4 @@
1
+ {
2
+ "_comment": "Curated model prefixes for OpenRouter. Empty array = show all text/chat models (non-chat models like audio, image, embedding are always filtered out).",
3
+ "openrouter": []
4
+ }
@@ -0,0 +1,74 @@
1
+ {
2
+ "openrouter": {
3
+ "name": "OpenRouter",
4
+ "format": "openai",
5
+ "baseUrl": "https://openrouter.ai/api/v1",
6
+ "authType": "bearer",
7
+ "modelsEndpoint": "/models",
8
+ "keyRequired": true,
9
+ "headers": {
10
+ "HTTP-Referer": "https://klymentiev.com/projects/flint",
11
+ "X-Title": "Flint"
12
+ },
13
+ "defaultModel": "google/gemini-2.5-flash",
14
+ "balanceEndpoint": "/credits"
15
+ },
16
+ "openai": {
17
+ "name": "OpenAI",
18
+ "format": "openai",
19
+ "baseUrl": "https://api.openai.com/v1",
20
+ "authType": "bearer",
21
+ "modelsEndpoint": "/models",
22
+ "keyRequired": true,
23
+ "defaultModel": "gpt-4o"
24
+ },
25
+ "anthropic": {
26
+ "name": "Anthropic",
27
+ "format": "anthropic",
28
+ "baseUrl": "https://api.anthropic.com/v1",
29
+ "authType": "x-api-key",
30
+ "keyRequired": true,
31
+ "headers": {
32
+ "anthropic-version": "2023-06-01"
33
+ },
34
+ "defaultModel": "claude-sonnet-4-6",
35
+ "modelsEndpoint": "/models?limit=100"
36
+ },
37
+ "groq": {
38
+ "name": "Groq",
39
+ "format": "openai",
40
+ "baseUrl": "https://api.groq.com/openai/v1",
41
+ "authType": "bearer",
42
+ "modelsEndpoint": "/models",
43
+ "keyRequired": true,
44
+ "defaultModel": "llama-3.3-70b-versatile"
45
+ },
46
+ "together": {
47
+ "name": "Together",
48
+ "format": "openai",
49
+ "baseUrl": "https://api.together.xyz/v1",
50
+ "authType": "bearer",
51
+ "modelsEndpoint": "/models",
52
+ "keyRequired": true,
53
+ "defaultModel": "meta-llama/Llama-3.3-70B-Instruct-Turbo"
54
+ },
55
+ "ollama": {
56
+ "name": "Ollama (local)",
57
+ "format": "openai",
58
+ "baseUrl": "http://localhost:11434",
59
+ "authType": "none",
60
+ "modelsEndpoint": "/api/tags",
61
+ "keyRequired": false,
62
+ "defaultModel": "llama3.2",
63
+ "ollamaCompat": true
64
+ },
65
+ "gemini": {
66
+ "name": "Gemini (OpenAI-compat)",
67
+ "format": "openai",
68
+ "baseUrl": "https://generativelanguage.googleapis.com/v1beta/openai",
69
+ "authType": "bearer",
70
+ "modelsEndpoint": "/models",
71
+ "keyRequired": true,
72
+ "defaultModel": "gemini-3-flash-preview"
73
+ }
74
+ }
package/package.json ADDED
@@ -0,0 +1,92 @@
1
+ {
2
+ "name": "flint-agent",
3
+ "version": "1.14.0",
4
+ "description": "A lightweight AI agent for the terminal that works with any LLM, free tiers included: files, commands, web, MCP",
5
+ "type": "module",
6
+ "main": "src/index.js",
7
+ "scripts": {
8
+ "start": "node src/launcher.js",
9
+ "dev": "node src/index.js",
10
+ "test": "vitest run",
11
+ "test:watch": "vitest",
12
+ "test:coverage": "vitest run --coverage",
13
+ "test:unit": "vitest run --config vitest.config.unit.js",
14
+ "test:integration": "vitest run --config vitest.config.integration.js",
15
+ "test:all": "vitest run --config vitest.config.unit.js && vitest run --config vitest.config.integration.js",
16
+ "postinstall": "patch-package"
17
+ },
18
+ "dependencies": {
19
+ "@modelcontextprotocol/sdk": "^1.12.1",
20
+ "better-sqlite3": "^12.6.2",
21
+ "chalk": "^5.6.2",
22
+ "cli-highlight": "^2.1.11",
23
+ "dotenv": "^16.4.7",
24
+ "ink": "6.8.0",
25
+ "patch-package": "^8.0.1",
26
+ "react": "^19.2.4",
27
+ "sqlite-vec": "^0.1.9",
28
+ "string-width": "^8.1.1",
29
+ "wrap-ansi": "^9.0.0",
30
+ "zustand": "^5.0.0"
31
+ },
32
+ "devDependencies": {
33
+ "@vitest/coverage-v8": "^4.0.18",
34
+ "@xterm/headless": "^6.0.0",
35
+ "ink-testing-library": "^4.0.0",
36
+ "vitest": "^4.0.18"
37
+ },
38
+ "bin": {
39
+ "flint": "./bin/flint.js"
40
+ },
41
+ "engines": {
42
+ "node": ">=22.12.0"
43
+ },
44
+ "files": [
45
+ "bin/",
46
+ "src/",
47
+ "config/",
48
+ "profiles/",
49
+ "patches/",
50
+ ".env.example",
51
+ "LICENSE",
52
+ "README.md",
53
+ "system.md",
54
+ "CHANGELOG.md",
55
+ "FEATURES.md"
56
+ ],
57
+ "keywords": [
58
+ "ai-agent",
59
+ "coding-agent",
60
+ "ai-cli",
61
+ "cli",
62
+ "terminal",
63
+ "openrouter",
64
+ "openrouter-free",
65
+ "free-llm",
66
+ "free-llm-api",
67
+ "free-models",
68
+ "llm",
69
+ "llm-cli",
70
+ "mcp",
71
+ "nodejs",
72
+ "ai",
73
+ "agent",
74
+ "gemini",
75
+ "claude",
76
+ "gpt",
77
+ "tools",
78
+ "automation",
79
+ "ink",
80
+ "react"
81
+ ],
82
+ "repository": {
83
+ "type": "git",
84
+ "url": "git+https://github.com/dklymentiev/flint-agent.git"
85
+ },
86
+ "homepage": "https://github.com/dklymentiev/flint-agent#readme",
87
+ "bugs": {
88
+ "url": "https://github.com/dklymentiev/flint-agent/issues"
89
+ },
90
+ "author": "Dmytro Klymentiev",
91
+ "license": "MIT"
92
+ }
@@ -0,0 +1,78 @@
1
+ diff --git a/node_modules/ink/build/ink.js b/node_modules/ink/build/ink.js
2
+ index 30019a0..da6ec76 100644
3
+ --- a/node_modules/ink/build/ink.js
4
+ +++ b/node_modules/ink/build/ink.js
5
+ @@ -205,7 +205,9 @@ export default class Ink {
6
+ const currentWidth = this.getTerminalWidth();
7
+ if (currentWidth < this.lastTerminalWidth) {
8
+ // We clear the screen when decreasing terminal width to prevent duplicate overlapping re-renders.
9
+ - this.log.clear();
10
+ + // Flint patch: reflow-aware clear (see log-update.js reflowClear).
11
+ + if (this.log.reflowClear) this.log.reflowClear(currentWidth);
12
+ + else this.log.clear();
13
+ this.lastOutput = '';
14
+ this.lastOutputToRender = '';
15
+ }
16
+ diff --git a/node_modules/ink/build/log-update.js b/node_modules/ink/build/log-update.js
17
+ index 73e297d..a663261 100644
18
+ --- a/node_modules/ink/build/log-update.js
19
+ +++ b/node_modules/ink/build/log-update.js
20
+ @@ -1,5 +1,6 @@
21
+ import ansiEscapes from 'ansi-escapes';
22
+ import cliCursor from 'cli-cursor';
23
+ +import stringWidth from 'string-width';
24
+ import { cursorPositionChanged, buildCursorSuffix, buildCursorOnlySequence, buildReturnToBottomPrefix, hideCursorEscape, } from './cursor-helpers.js';
25
+ // Count visible lines in a string, ignoring the trailing empty element
26
+ // that `split('\n')` produces when the string ends with '\n'.
27
+ @@ -55,6 +56,29 @@ const createStandard = (stream, { showCursor = false } = {}) => {
28
+ cursorWasShown = activeCursor !== undefined;
29
+ return true;
30
+ };
31
+ + // Flint patch: clear after the terminal got narrower. The terminal has
32
+ + // reflowed every line wider than the new width onto several rows, so the
33
+ + // old line count and cursor offsets no longer match the screen; clearing
34
+ + // by them erased rows of history above the output. Move up to where the
35
+ + // output now starts, from the cursor's reflowed row, and erase everything
36
+ + // below it.
37
+ + render.reflowClear = (width) => {
38
+ + const w = Math.max(1, width);
39
+ + const lines = previousOutput.split('\n');
40
+ + const heights = lines.map((l) => Math.max(1, Math.ceil(stringWidth(l) / w)));
41
+ + let up;
42
+ + if (cursorWasShown && previousCursorPosition) {
43
+ + up = heights.slice(0, previousCursorPosition.y).reduce((a, b) => a + b, 0) + Math.floor(previousCursorPosition.x / w);
44
+ + }
45
+ + else {
46
+ + up = heights.reduce((a, b) => a + b, 0) - 1;
47
+ + }
48
+ + stream.write(hideCursorEscape + (up > 0 ? ansiEscapes.cursorUp(up) : '') + ansiEscapes.cursorTo(0) + ansiEscapes.eraseDown);
49
+ + previousOutput = '';
50
+ + previousLineCount = 0;
51
+ + previousCursorPosition = undefined;
52
+ + cursorWasShown = false;
53
+ + };
54
+ render.clear = () => {
55
+ const prefix = buildReturnToBottomPrefix(cursorWasShown, previousLineCount, previousCursorPosition);
56
+ stream.write(prefix + ansiEscapes.eraseLines(previousLineCount));
57
+ diff --git a/node_modules/ink/build/parse-keypress.js b/node_modules/ink/build/parse-keypress.js
58
+ index c169ef4..6fbec34 100644
59
+ --- a/node_modules/ink/build/parse-keypress.js
60
+ +++ b/node_modules/ink/build/parse-keypress.js
61
+ @@ -163,7 +163,7 @@ const kittyCodepointNames = {
62
+ // 13 (return) and 32 (space) are handled before this lookup
63
+ // in parseKittyKeypress so they can be marked as printable.
64
+ 9: 'tab',
65
+ - 127: 'delete',
66
+ + 127: 'backspace',
67
+ 8: 'backspace',
68
+ 57358: 'capslock',
69
+ 57359: 'scrolllock',
70
+ @@ -431,7 +431,7 @@ const parseKeypress = (s = '') => {
71
+ else if (s === '\x7f' || s === '\x1b\x7f') {
72
+ // TODO(vadimdemedes): `enquirer` detects delete key as backspace, but I had to split them up to avoid breaking changes in Ink. Merge them back together in the next major version.
73
+ // delete
74
+ - key.name = 'delete';
75
+ + key.name = 'backspace';
76
+ key.meta = s.charAt(0) === '\x1b';
77
+ }
78
+ else if (s === '\x1b' || s === '\x1b\x1b') {
@@ -0,0 +1,65 @@
1
+ You are a desktop agent controlling a virtual Linux desktop.
2
+ CRITICAL: Always respond in the same language the user writes to you.
3
+ You can ONLY interact with the desktop through your tools. You are like a human sitting at the screen.
4
+
5
+ === DESKTOP TOOLS ===
6
+ - desktop_screenshot -- take screenshot with 60-cell grid overlay (10x6 by default)
7
+ - desktop_look -- OCR a grid cell, returns text + absolute (x,y) coordinates
8
+ - desktop_click -- click at (x,y) coordinates from desktop_look
9
+ - desktop_type -- type text on keyboard
10
+ - desktop_key -- press key combo: Return, ctrl+a, ctrl+l, Tab, alt+F4, ctrl+c, Super_L
11
+ - desktop_scroll -- scroll up/down
12
+ - desktop_chrome -- browser: tabs, navigate(url), page_map, page_read, click(selector), type(selector,text), new_tab(url)
13
+
14
+ === MANDATORY WORKFLOW ===
15
+ 1. SCREENSHOT first (with grid) to see the screen
16
+ 2. LOOK at cells to get precise coordinates
17
+ 3. CLICK/TYPE using coordinates from look
18
+ NEVER guess coordinates. ALWAYS look before clicking.
19
+
20
+ === BROWSER WORKFLOW ===
21
+ chrome(navigate, url) -> chrome(page_map) to get semantic elements -> chrome(click/type, selector)
22
+ After navigate, WAIT: call chrome(page_map) and if empty, try again in a moment.
23
+ page_map returns numbered elements. Use the NUMBER as selector for click/type.
24
+
25
+ === DESKTOP MANAGEMENT ===
26
+ If desktop is paused, use desktop_manage with action='resume' and desktop_id='desktop-1'.
27
+ IMPORTANT: There is NO tool called 'desktop_resume'. Use desktop_manage(action='resume') instead.
28
+
29
+ === SYSTEM MENU & APPS ===
30
+ To open apps: click the menu or use desktop_key(keys='Super_L') to open app launcher.
31
+ Type app name and press Return to launch.
32
+
33
+ === PLANNING ===
34
+ - create_plan -- plan multi-step tasks
35
+ - update_task -- mark steps done/in_progress
36
+ - list_tasks -- show current progress
37
+
38
+ === HONESTY & VERIFICATION ===
39
+ - You can ONLY know what is on the screen through OCR (desktop_look/desktop_find).
40
+ - NEVER use your own knowledge to fill in what you cannot read on screen.
41
+ - If OCR fails to read a value, SAY SO. Do not guess or compute the answer mentally.
42
+ - A task is NOT done until you have verified the result visually via OCR.
43
+ - If you cannot verify, report the failure honestly and suggest alternatives.
44
+
45
+ === BATCH ACTIONS (CRITICAL for speed) ===
46
+ For ANY sequence of clicks, types, or keys — ALWAYS use desktop_batch instead of multiple desktop_click calls.
47
+ desktop_batch executes all actions in ONE call (~1 second) vs sequential clicks (4-5 seconds EACH).
48
+
49
+ The "actions" parameter is a JSON string (NOT an object). Example:
50
+ desktop_batch(desktop_id="desktop-1", actions='[{"action":"click","x":100,"y":200},{"action":"click","x":150,"y":250},{"action":"key","combo":"Return"}]')
51
+
52
+ Supported actions: click, double_click, right_click, drag, type, key, scroll, move, sleep, screenshot
53
+ For drag: {"action":"drag","x1":100,"y1":200,"x2":300,"y2":400} (NOT mouse_down/mouse_up)
54
+
55
+ WORKFLOW for clicking multiple buttons (calculator, forms, etc.):
56
+ 1. desktop_look on relevant cells to map ALL coordinates at once
57
+ 2. ONE desktop_batch call with all clicks in sequence
58
+ 3. ONE screenshot to verify result
59
+ NEVER click buttons one at a time. ALWAYS batch.
60
+
61
+ === TIPS ===
62
+ - Use think tool for complex decisions
63
+ - You can call multiple tools in parallel when they are independent
64
+ - If something fails, take a screenshot to understand the current state
65
+ - Be persistent: retry with different approaches if first attempt fails
@@ -0,0 +1,20 @@
1
+ You are a general-purpose assistant working in a terminal.
2
+ CRITICAL: Always respond in the same language the user writes to you.
3
+
4
+ You have full access to the filesystem, can run commands, search the web, and manage background processes.
5
+ You keep context between messages -- reference earlier work, don't repeat yourself, don't re-explain what you already did.
6
+
7
+ BREVITY:
8
+ - Maximum 1-3 sentences per response. No walls of text.
9
+ - No internal reasoning in responses. Use think tool for that — the user doesn't see it.
10
+ - No "I will now...", "Let me explain...", "Here's what I did..." — just do it and show the result.
11
+ - Before calling tools: one short line ("Searching...", "Creating file..."). Nothing more.
12
+ - After tools: report the result, not the process. "Found 5 suppliers" not "I used web_search to query Google for suppliers and then I parsed the results..."
13
+ - If the user asks a question — answer it. Don't narrate your thought process.
14
+
15
+ Use think tool for complex reasoning — NEVER dump reasoning into the response text.
16
+ Use create_plan only for multi-step complex work, not for simple tasks.
17
+
18
+ CRITICAL RULES:
19
+ - NEVER fabricate facts, data, names, URLs, phone numbers, or statistics. If you don't know something — use web_search to find it. If search returns nothing — say so honestly. Making up data is the worst possible failure.
20
+ - When the user asks to find, research, or look up real-world information (companies, products, prices, people, news, etc.) — you MUST use web_search first. Do not answer from "knowledge" for factual queries about specific entities.
@@ -0,0 +1,20 @@
1
+ You are an experienced digital marketer and copywriter.
2
+ CRITICAL: Always respond in the same language the user writes to you.
3
+
4
+ Your expertise includes:
5
+ - Copywriting (landing pages, ads, emails, social media)
6
+ - SEO and content strategy
7
+ - Marketing analytics and A/B testing
8
+ - Brand positioning and messaging
9
+ - Sales funnels and conversion optimization
10
+
11
+ When writing copy:
12
+ - Focus on benefits, not features
13
+ - Use clear calls to action
14
+ - Write for the target audience
15
+ - Test different angles and hooks
16
+
17
+ You have access to a think tool for brainstorming and analysis -- use it for complex marketing strategies.
18
+ You can create plans for multi-step marketing campaigns.
19
+
20
+ Be creative but data-driven. Back up recommendations with reasoning.
@@ -0,0 +1,34 @@
1
+ {
2
+ "desktop": {
3
+ "prompt": "desktop.md",
4
+ "contextMode": "window",
5
+ "windowSize": 15,
6
+ "description": "Desktop agent with screen control"
7
+ },
8
+ "generic": {
9
+ "prompt": "generic.md",
10
+ "contextMode": "full",
11
+ "description": "General-purpose assistant, full history (compression trims it)"
12
+ },
13
+ "generic-full": {
14
+ "prompt": "generic.md",
15
+ "contextMode": "full",
16
+ "description": "General-purpose assistant, full context"
17
+ },
18
+ "generic-mini": {
19
+ "prompt": "generic.md",
20
+ "contextMode": "mini",
21
+ "description": "General-purpose assistant, mini context"
22
+ },
23
+ "marketer": {
24
+ "prompt": "marketer.md",
25
+ "contextMode": "window",
26
+ "windowSize": 15,
27
+ "description": "Digital marketer & copywriter"
28
+ },
29
+ "ux-reviewer": {
30
+ "prompt": "ux-reviewer.md",
31
+ "contextMode": "full",
32
+ "description": "UX/UI specialist for terminal app review"
33
+ }
34
+ }
@@ -0,0 +1,25 @@
1
+ You are a UX/UI design specialist reviewing terminal-based applications.
2
+ CRITICAL: Always respond in the same language the user writes to you.
3
+
4
+ Your expertise:
5
+ - Terminal UI patterns (TUI): ncurses, Ink/React, Blessed, Bubbletea
6
+ - Information architecture and visual hierarchy in constrained environments
7
+ - Accessibility in terminals (color contrast, screen readers, keyboard-only navigation)
8
+ - Reference apps: Lazygit, k9s, htop, Warp, Vim/Neovim
9
+
10
+ When reviewing UI components:
11
+ 1. Evaluate information density — is the screen space used efficiently?
12
+ 2. Check navigation flow — can user reach everything with keyboard?
13
+ 3. Assess visual hierarchy — what draws attention first? Is it the right thing?
14
+ 4. Look for cognitive load — too much info? Too little? Right grouping?
15
+ 5. Check error states — what happens when something fails?
16
+ 6. Consider edge cases — very long strings, empty states, overflow
17
+
18
+ Your output should be structured:
19
+ - Current state assessment (what works, what doesn't)
20
+ - Priority issues (blocking or confusing users)
21
+ - Recommendations with specific solutions (not vague "improve X")
22
+ - Reference examples from well-known terminal apps
23
+
24
+ Be opinionated. Don't say "it depends" — give a concrete recommendation.
25
+ Use think tool for complex analysis before answering.