@fml-inc/fml 0.6.1 → 0.8.0-rc.1

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 (46) hide show
  1. package/.claude-plugin/plugin.json +2 -4
  2. package/README.md +316 -70
  3. package/agent-assets/fml/SKILL.md +180 -0
  4. package/bin/fml +4 -18
  5. package/bin/hook-handler +7 -0
  6. package/bin/mcp-server +4 -18
  7. package/bin/observer +6 -0
  8. package/dist/chunk-7DR5X7XI.js +1522 -0
  9. package/dist/chunk-CK5MEL5J.js +140 -0
  10. package/dist/chunk-DEMVOVVY.js +4442 -0
  11. package/dist/chunk-F66IBM3Z.js +1037 -0
  12. package/dist/chunk-HUR2HCUG.js +953 -0
  13. package/dist/chunk-I4GZPTBM.js +109 -0
  14. package/dist/chunk-JXSSPQ5B.js +3331 -0
  15. package/dist/{chunk-PZ5AY32C.js → chunk-MLKGABMK.js} +0 -1
  16. package/dist/{chunk-2H6D7RUN.js → chunk-P3QLARXE.js} +36 -23
  17. package/dist/chunk-T5YVLSUC.js +138 -0
  18. package/dist/cli.js +7623 -990
  19. package/dist/{esm-2EUDFZWP.js → esm-4YKLKFRX.js} +546 -741
  20. package/dist/hook-handler.js +190 -0
  21. package/dist/mcp/server.js +112 -98
  22. package/dist/observer-server.js +1566 -0
  23. package/dist/sync-cycle.js +31 -0
  24. package/dist/token-store-R7WXEPLI.js +27 -0
  25. package/hooks/hooks.json +290 -0
  26. package/package.json +24 -27
  27. package/dist/chunk-2H6D7RUN.js.map +0 -1
  28. package/dist/chunk-PZ5AY32C.js.map +0 -1
  29. package/dist/chunk-VDW5L7OB.js +0 -405
  30. package/dist/chunk-VDW5L7OB.js.map +0 -1
  31. package/dist/chunk-YH5ROR7G.js +0 -69
  32. package/dist/chunk-YH5ROR7G.js.map +0 -1
  33. package/dist/chunk-ZFUJ5ZQP.js +0 -41
  34. package/dist/chunk-ZFUJ5ZQP.js.map +0 -1
  35. package/dist/cli.js.map +0 -1
  36. package/dist/daemon-J27JBWLV.js +0 -17
  37. package/dist/daemon-J27JBWLV.js.map +0 -1
  38. package/dist/daemon-utils-OODBIYB7.js +0 -10
  39. package/dist/daemon-utils-OODBIYB7.js.map +0 -1
  40. package/dist/esm-2EUDFZWP.js.map +0 -1
  41. package/dist/mcp/server.js.map +0 -1
  42. package/dist/postinstall.js +0 -16
  43. package/dist/postinstall.js.map +0 -1
  44. package/dist/token-store-JZJ3FJHA.js +0 -16
  45. package/dist/token-store-JZJ3FJHA.js.map +0 -1
  46. package/scripts/postinstall.cjs +0 -25
@@ -1,13 +1,11 @@
1
1
  {
2
2
  "name": "fml",
3
- "version": "0.6.1",
3
+ "version": "0.8.0-rc.1",
4
4
  "description": "FML agent tools for Claude Code",
5
5
  "mcpServers": {
6
6
  "fml": {
7
7
  "command": "node",
8
- "args": [
9
- "${CLAUDE_PLUGIN_ROOT}/bin/mcp-server"
10
- ]
8
+ "args": ["${CLAUDE_PLUGIN_ROOT}/bin/mcp-server"]
11
9
  }
12
10
  }
13
11
  }
package/README.md CHANGED
@@ -1,111 +1,357 @@
1
- # FML
1
+ # FML CLI
2
2
 
3
- Agent tools for AI coding assistants. Installs as a [Claude Code plugin](https://docs.anthropic.com/en/docs/claude-code/plugins) with MCP tools for session analytics, cost tracking, integrations, and team workflows — powered by [Panopticon](https://github.com/fml-inc/panopticon) for local data collection.
3
+ `@fml-inc/fml` is the single published FML command-line package. It provides
4
+ the `fml` command, account and organization authentication, agent MCP
5
+ integration, cloud-backed product commands, and raw artifact sync.
6
+
7
+ Panopticon is an internal workspace engine under `packages/panopticon`. Its
8
+ raw-sync implementation is bundled into this package at build time; users do
9
+ not install or run a second Panopticon package.
4
10
 
5
11
  ## Install
6
12
 
13
+ Node.js 22.15 or newer and pnpm are required.
14
+
7
15
  ```bash
8
- npm install -g @fml-inc/fml
16
+ pnpm add --global @fml-inc/fml
17
+ fml install
18
+ fml login
19
+ fml org
20
+ fml start
9
21
  ```
10
22
 
11
- This installs the plugin, registers hooks and MCP tools in Claude Code, and bootstraps Panopticon for local data collection. Start a new session to activate.
23
+ Installing the package does not change agent configuration. Run `fml install`
24
+ explicitly to register the FML Claude Code plugin, install the agent-native FML
25
+ skill, configure the FML MCP server, and register capture-only lifecycle hooks
26
+ for supported agents. Invoke the skill as `/fml review` in Claude, Gemini, or
27
+ Grok, and as `$fml review` in Codex. Review runs inside the agent from the
28
+ packaged skill; it is not an `fml review` CLI command. Start a new agent session
29
+ after installing so it picks up the integration. FML pre-approves only the
30
+ isolated command hooks it installs for Codex; use `/hooks` to review or disable
31
+ them.
32
+
33
+ The Claude plugin is MCP-only. FML installs the workflow through each host's
34
+ native skill directory so it keeps the bare `fml` name without a second,
35
+ plugin-namespaced skill.
36
+
37
+ For a coding agent operating in a sandbox, use the
38
+ [agent installation guide](./docs/agent_installation_guide.md).
39
+
40
+ ## Upgrading from standalone Panopticon
12
41
 
13
- Then sign in:
42
+ Earlier releases shipped as a separate `@fml-inc/panopticon` package that
43
+ installed its own Claude plugin, agent hooks, MCP server, OpenTelemetry
44
+ settings, and shell environment. `fml install` does not migrate that install.
45
+ Retire it first, from the machine that has it, before installing FML:
14
46
 
15
47
  ```bash
16
- fml login
48
+ panopticon uninstall --purge
17
49
  ```
18
50
 
19
- ## For LLM agents
51
+ `panopticon uninstall --purge` stops the standalone daemon and removes its
52
+ plugin, hooks, MCP registrations, shell block, and generated data directory.
53
+ Then follow the [Install](#install) steps above for a clean setup. If the old
54
+ `panopticon` command is already gone, reinstall `@fml-inc/panopticon` just to
55
+ run its uninstall, or clean up by hand: remove the `# >>> panopticon >>>` block
56
+ from your shell profile, delete the data directory (macOS:
57
+ `~/Library/Application Support/panopticon`; Linux: `~/.local/share/panopticon`;
58
+ Windows: `%APPDATA%\panopticon`), and remove any leftover `panopticon` entries
59
+ from the Claude plugin registration (`~/.claude/settings.json` and
60
+ `~/.claude/plugins/`), agent hook configs (`~/.codex/config.toml`,
61
+ `~/.codex/hooks.json`, `~/.gemini/settings.json`, `~/.grok/hooks/`), and MCP
62
+ server registrations in those same agent config files.
20
63
 
21
- Setting up FML from inside a coding-agent sandbox (Claude Code, Codex, Gemini CLI, etc.)? Paste this to your agent:
64
+ ## Raw artifact sync
22
65
 
66
+ Sync uploads original, file-backed agent artifacts to FML. It does not parse
67
+ them into local session, message, tool-call, or scanner tables. Server-side
68
+ scanners own parsing and projections.
69
+
70
+ Discovery covers supported local stores across Claude Code, Codex, Gemini,
71
+ Grok, Cursor, Pi, Copilot CLI, and Factory Droid, including archived Codex
72
+ sessions. Availability depends on which harnesses have written artifacts on
73
+ the machine.
74
+
75
+ Sync has one persistent setting: enabled or disabled. It defaults to enabled.
76
+ The backend environment, login, and selected organization determine the upload
77
+ destination; there is no user-configurable sync-target list.
78
+
79
+ ```bash
80
+ fml sync # Discover and drain pending raw artifacts
81
+ fml sync --dry-run # Show what would be discovered without changing the queue
82
+ fml sync status # Show enabled state, queue counts, and byte watermarks
83
+ fml sync disable # Stop discovery and upload
84
+ fml sync enable # Allow discovery and upload again
85
+ fml sync reset # Clear watermarks and replay every local artifact from byte zero
86
+ fml start # Start the observer and continuously run enabled raw sync
87
+ fml stop # Stop the observer and disable raw sync
23
88
  ```
24
- Follow the installation instructions here: https://github.com/fml-inc/observe/blob/main/docs/agent_installation_guide.md
25
- ```
26
89
 
27
- The guide covers: `npm install -g @fml-inc/fml` → `fml install` → `fml login --device` (the agent relays the verification URL to you, you paste the code back) → `fml doctor`. No browser, no `gh` CLI, no manual shell-profile edits needed.
90
+ `fml sync reset` preserves the enabled/disabled setting and source files. It
91
+ clears local upload progress and gives tracked artifacts fresh generations, so
92
+ the next enabled `fml sync` performs a full replay. Reset refuses to race an
93
+ active sync.
94
+
95
+ For automation, the sync commands support `--json`. `fml start` enables raw
96
+ sync and launches a detached observer with a loopback-only HTTP endpoint. The
97
+ observer runs sync immediately, retries in the background, and follows later
98
+ `fml env` and `fml org` changes. `fml sync disable` pauses only raw discovery
99
+ and upload. Capture-only hooks continue writing to their durable local outbox
100
+ and uploading in the background. `fml stop` disables raw sync, records an
101
+ explicit hook-capture pause, and stops the complete observer runtime. Either
102
+ `fml start` or `fml sync enable` clears that pause. A crash or reboot does not
103
+ pause capture: handler inbox files remain durable until the observer returns.
28
104
 
29
- ## What it does
105
+ The observer keeps a SQLite database for runtime bookkeeping and the
106
+ durable hook outbox. It is operational state, not a local copy of session,
107
+ message, scanner, or analytics tables. Hermes discovery and sync remain
108
+ deferred.
30
109
 
31
- **Local observability** — Panopticon captures OpenTelemetry signals, hook events, session files, and API traffic from Claude Code, Gemini CLI, and Codex CLI into a local SQLite database.
110
+ The database is `panopticon.db` under FML's platform-native operational-state
111
+ root:
32
112
 
33
- **MCP tools for your agent** — Once installed, Claude Code gets tools to query your sessions, costs, activity, and connected integrations directly in conversation.
113
+ | Platform | Account/configuration (`FML_DATA_DIR`) | Operational database |
114
+ | -------- | -------------------------------------- | ----------------------------------------------------- |
115
+ | macOS | `~/Library/Application Support/fml` | `~/Library/Application Support/fml/panopticon.db` |
116
+ | Linux | `${XDG_DATA_HOME:-~/.local/share}/fml` | `${XDG_STATE_HOME:-~/.local/state}/fml/panopticon.db` |
117
+ | Windows | `%APPDATA%\fml` | `%LOCALAPPDATA%\fml\panopticon.db` |
34
118
 
35
- **Cloud sync** — Optionally sync local data to the FML dashboard for team-wide visibility, config snapshots, and automations.
119
+ The cutover is forward-only: the observer starts with a clean database at the
120
+ new path and does not migrate or delete the former
121
+ `~/.fml/panopticon/observer.db`. `fml start` reports that retained path whenever
122
+ the file still exists; when replacing a live legacy observer, it also reports
123
+ the old observer's pending row count. The PID state, lease/lock, endpoint,
124
+ auth-token files, hook inbox, and raw-sync watermarks remain under the
125
+ separately configurable observer directory.
126
+
127
+ Use `FML_STATE_DIR` to relocate the operational database and `FML_DATA_DIR` to
128
+ relocate account and environment configuration. For compatibility, an explicit
129
+ `FML_DATA_DIR` also relocates the database when `FML_STATE_DIR` is absent. It
130
+ does not relocate logs or observer coordination state: those retain their
131
+ platform defaults unless `FML_LOG_DIR` or an observer override is set.
132
+ `FML_OBSERVER_DIR` directly relocates observer coordination state;
133
+ `PANOPTICON_HOME` is a legacy alias for that directory and `FML_HOME` is a
134
+ legacy parent whose `panopticon` child is used. These observer-only aliases do
135
+ not relocate the database or account configuration. Because that pattern used
136
+ to isolate the pre-cutover database as well, `fml start` and the observer warn
137
+ at startup when an observer-only alias is set without `FML_STATE_DIR` or
138
+ `FML_DATA_DIR`; set one of those to choose the database root explicitly.
139
+
140
+ Every explicit FML directory override must be absolute; relative values are
141
+ rejected so processes launched from different working directories cannot
142
+ silently select different state. Relative XDG and Windows shell-directory
143
+ variables are ignored in favor of the platform fallback.
144
+
145
+ The filesystems containing `FML_STATE_DIR` and `FML_OBSERVER_DIR` must support
146
+ same-directory hard links. FML uses that atomic primitive to publish complete
147
+ observer lease records without exposing a partially written database lock;
148
+ standard APFS, ext4, and NTFS volumes support it.
149
+
150
+ For multiple fully isolated FML instances, configure absolute, dedicated
151
+ `FML_DATA_DIR`, `FML_LOG_DIR`, and `FML_OBSERVER_DIR` roots per instance.
152
+ `FML_DATA_DIR` also isolates the database unless a separate `FML_STATE_DIR` is
153
+ set. Configuring a distinct `FML_OBSERVER_PORT` is also recommended. A
154
+ database-scoped runtime lease rejects a second observer that resolves to the
155
+ same `panopticon.db`; give that instance a different data or state root and
156
+ start it again.
157
+
158
+ ## Hook capture
159
+
160
+ FML installs capture-only hooks for Claude Code, Codex, Gemini CLI, and Grok
161
+ CLI. It also configures direct MCP entries for Codex, Gemini, Grok, and Claude
162
+ Desktop. The hook handler reads the agent's JSON event, first commits an
163
+ owner-only per-delivery file, then sends it only to the authenticated loopback
164
+ observer, and always returns an empty JSON object. It does not make permission
165
+ decisions, inject context, or contact FML directly.
166
+
167
+ The observer commits each event to SQLite before removing its handler-side
168
+ delivery file. Files left by a stopped, restarting, busy, or unavailable
169
+ observer are replayed with the same sync ID, so a timeout cannot create a
170
+ duplicate or silently drop the event. A separate uploader sends stable,
171
+ idempotent batches through `/v2/sync` to the selected FML environment and
172
+ account, then removes local rows only after the server acknowledges them.
173
+ Repository authorization is evaluated per row across every organization the
174
+ account can access; hook delivery does not depend on the currently selected
175
+ organization. `fml status` reports both the handler inbox and SQLite outbox.
176
+
177
+ Each capture with known login state is durably bound to its exact FML URL,
178
+ and stable account identity; switching environments or accounts cannot upload
179
+ or acknowledge another destination's rows. Captures made while logged out
180
+ remain unbound until the first authenticated destination atomically claims that
181
+ backlog.
182
+
183
+ The handler-side inbox is a short-lived durability bridge for times when the
184
+ observer is stopped or unavailable. It is bounded independently from the
185
+ SQLite spool: by default it accepts at most 512 MiB or 10,000 delivery files,
186
+ whichever is reached first. At a limit it preserves older committed files,
187
+ refuses the newest inbox write, and still fails open for the invoking agent; a
188
+ running observer can still accept that event directly. `fml status` reports
189
+ the active limits and cumulative capacity refusals.
190
+
191
+ Set `FML_HOOK_INBOX_MAX_BYTES` and `FML_HOOK_INBOX_MAX_ENTRIES` in the coding
192
+ agent's environment to change these limits. Bytes accept the same `B`, `KiB`,
193
+ `MiB`, and `GiB` suffixes described below; entries are positive integers. An
194
+ explicit `unbounded` opts out of either limit. These settings affect only the
195
+ per-delivery file inbox and do not change normal SQLite spool retention.
196
+
197
+ The hook spool is unbounded by default. To bound it, set
198
+ `FML_HOOK_SPOOL_MAX_BYTES` when starting the observer:
199
+
200
+ ```bash
201
+ FML_HOOK_SPOOL_MAX_BYTES=512MiB fml start
202
+ ```
203
+
204
+ The value is a positive integer in bytes with an optional `B`, `KiB`, `MiB`,
205
+ or `GiB` suffix. Unset it, or set it to `unbounded`, to retain the full spool
206
+ without a size limit. Invalid values (including `0`) stop observer startup
207
+ instead of silently disabling the limit. Restart a running observer after
208
+ changing the setting.
209
+
210
+ This is a logical-content limit: it counts the UTF-8 bytes retained in hook
211
+ fields and their destination or rejection metadata across pending and
212
+ quarantined rows, not SQLite page, index, or WAL overhead. When the limit is
213
+ exceeded, the observer evicts the oldest quarantined rows first and then the
214
+ oldest pending rows. It never fails a hook invocation merely because the spool
215
+ is full. `fml status` reports current logical bytes, the configured maximum,
216
+ cumulative eviction counts and bytes, and the last eviction time.
217
+
218
+ Terminally rejected rows are retained for 30 days by default, independently
219
+ of the pending spool's unbounded default. Set
220
+ `FML_HOOK_QUARANTINE_MAX_AGE_DAYS` to a positive integer to change that window,
221
+ or to `unbounded` to retain quarantine rows until the byte bound evicts them.
222
+ Expired quarantine rows contribute to the same persisted eviction counters.
223
+ Retryable pending rows are never removed by this age policy.
224
+
225
+ The spool retains complete hook payloads and extracted fields, which can
226
+ include prompts, commands, file paths, plans, and tool output. FML-created
227
+ directories request owner-only permissions, and the SQLite database and
228
+ sidecars are tightened to owner-only modes on platforms that support POSIX
229
+ modes. An existing caller-supplied state directory retains its directory mode.
36
230
 
37
231
  ## MCP tools
38
232
 
39
- These tools are available to Claude Code via the plugin:
40
-
41
- | Tool | Description |
42
- |------|-------------|
43
- | `get_engineering_activity` | Activity summary — sessions, prompts, tools, costs |
44
- | `list_engineering_sessions` | List recent sessions with stats |
45
- | `search_engineering_sessions` | Search across all sessions |
46
- | `get_session_timeline` | Messages and tool calls for a session |
47
- | `get_session_turns` | Per-turn token usage for a session |
48
- | `get_ai_spending` | Token usage and cost breakdowns |
49
- | `whoami` | Current auth and org status |
50
- | `fml_list_integrations` | Connected integrations (Slack, GitHub, Linear, Sentry, etc.) |
51
- | `fml_query_*` | Query connected integrations directly |
52
- | `fml_list_messages` | Conversation messages |
53
- | `fml_search_analysis` | Search codebase analysis results |
54
- | `fml_run_analysis_workflow` | Run deep analysis workflows |
55
- | `fml_list_skills` | Browse and load skills |
56
- | `list_repo_configs` | Team config snapshots |
57
-
58
- ## CLI
233
+ The MCP server exposes FML tools for session analytics, cost tracking,
234
+ integrations, team workflows, and account context, including:
235
+
236
+ | Tool | Description |
237
+ | ----------------------------- | ----------------------------------------------------------- |
238
+ | `get_engineering_activity` | Activity summary across sessions, prompts, tools, and costs |
239
+ | `list_engineering_sessions` | List recent sessions with stats |
240
+ | `search_engineering_sessions` | Search across sessions |
241
+ | `get_session_timeline` | Messages and tool calls for a session |
242
+ | `get_session_turns` | Per-turn token usage for a session |
243
+ | `get_ai_spending` | Token usage and cost breakdowns |
244
+ | `whoami` | Current auth and organization status |
245
+ | `fml_list_integrations` | Connected integrations |
246
+ | `fml_query_*` | Query connected integrations |
247
+ | `fml_list_messages` | Conversation messages |
248
+ | `fml_search_analysis` | Search codebase analysis results |
249
+ | `fml_run_analysis_workflow` | Run analysis workflows |
250
+ | `fml_list_skills` | Browse and load skills |
251
+ | `list_repo_configs` | Team configuration snapshots |
252
+
253
+ For backend tools not yet exposed as dedicated MCP tools, use the dynamic
254
+ catalog:
59
255
 
256
+ ```bash
257
+ fml tools list --json
258
+ fml tools describe <tool-name> --json
259
+ fml tools call <tool-name> --args '{"key":"value"}'
60
260
  ```
61
- fml install Register plugin, hooks, and daemons
62
- fml uninstall Remove plugin and hooks
63
- --target <t> Target: claude, gemini, codex, claude-desktop, all
64
- --purge Also remove all data, logs, and auth tokens
65
- fml update Update to the latest version
66
-
67
- fml login Sign in to your FML account
68
- fml logout Sign out and clear credentials
69
- fml org [slug] Show or select organization
70
- fml status Show auth and daemon status
71
- fml doctor Check configuration and connectivity
72
-
73
- fml open Open FML dashboard in browser
74
- fml start Start panopticon server
75
- fml stop Stop panopticon server
76
-
77
- fml activity Activity summary
78
- --since <duration> Time window (e.g. "24h", "7d")
261
+
262
+ ## CLI overview
263
+
264
+ ```text
265
+ fml install Register FML agent integrations and the MCP server
266
+ fml uninstall Remove agent integration; add --purge to remove local state
267
+ fml update Update @fml-inc/fml with pnpm
268
+
269
+ fml start Start the local observer and continuous raw sync
270
+ fml stop Stop the local observer and disable raw sync
271
+
272
+ fml login Sign in to FML
273
+ fml logout Clear stored credentials
274
+ fml org [slug] Show or select an organization
275
+ fml env [name-or-url] Show or select a backend environment
276
+ fml status Show auth, environment, and raw-sync status
277
+ fml doctor Check auth, environment, organization, raw sync, and API access
278
+ fml open Open the FML dashboard
279
+
280
+ fml sync Upload raw local artifacts
281
+ fml sync enable Enable raw artifact sync
282
+ fml sync disable Disable raw artifact sync
283
+ fml sync status Show queue counts and byte watermarks
284
+ fml sync reset Replay all raw artifacts from byte zero
285
+
286
+ fml tools Browse and invoke backend tools
287
+ fml activity Show an activity summary
79
288
  fml sessions List recent sessions
80
- fml timeline <id> Events for a session
81
- fml spending Token usage and cost breakdown
82
- fml search <query> Search across sessions
83
-
84
- fml sync setup Configure sync targets
85
- fml sync list List sync targets
86
- fml sync add <n> <url> Add a sync target
87
- fml sync remove <name> Remove a sync target
88
- fml sync status Show sync status
89
- fml sync reset [name] Reset sync watermarks
289
+ fml timeline <id> Show events for a session
290
+ fml spending Show token usage and cost breakdowns
291
+ fml search <query> Search sessions
90
292
  ```
91
293
 
294
+ Run `fml --help` or `fml commands` for the complete command inventory.
295
+
92
296
  ## Development
93
297
 
298
+ Run from the repository root:
299
+
94
300
  ```bash
95
- pnpm install # Install dependencies
96
- pnpm dev # Watch mode (tsup)
97
- pnpm test # Run tests (Vitest)
98
- pnpm type-check # Type check
301
+ pnpm install
302
+ pnpm --filter @fml-inc/fml type-check
303
+ pnpm --filter @fml-inc/fml test
304
+ pnpm --filter @fml-inc/fml build
99
305
  ```
100
306
 
101
- To test the full install flow:
307
+ Build, pack, and install the same artifact that will be published:
102
308
 
103
309
  ```bash
104
- pnpm build && pnpm pack
105
- npm install -g ./fml-inc-fml-*.tgz
310
+ pnpm --filter @fml-inc/fml pack:local
311
+ pnpm add --global ./apps/cli/fml-inc-fml-*.tgz
312
+ fml --version
106
313
  fml install
107
314
  ```
108
315
 
316
+ The packed manifest must not contain runtime dependencies on
317
+ `@fml/panopticon` or `@fml/agent-targets`; both private workspace packages are
318
+ bundled into the CLI.
319
+
320
+ ## Release
321
+
322
+ The [FML CLI release workflow](../../.github/workflows/publish-fml-cli.yml)
323
+ publishes the exact package that passes the packed-install smoke test. Create a
324
+ tag named `fml-v<semver>` on a commit reachable from `main`, then push the tag:
325
+
326
+ ```bash
327
+ git tag -a fml-v0.8.0 -m "Release FML CLI 0.8.0"
328
+ git push origin fml-v0.8.0
329
+ ```
330
+
331
+ Stable versions use npm's default `latest` tag. SemVer prereleases such as
332
+ `fml-v0.9.0-beta.1` publish under `next`. Each release must advance the version
333
+ currently assigned to its npm channel; the workflow rejects stable versions
334
+ that do not advance `latest` and prereleases that do not advance `next`.
335
+ Release tags may not contain SemVer build metadata. Keep
336
+ `apps/cli/package.json` at `0.0.0-dev` on `main`; the workflow stamps the
337
+ release version before building.
338
+
339
+ The `@fml-inc/fml` package must have one npm trusted publisher configured with
340
+ these exact values:
341
+
342
+ - Provider: GitHub Actions
343
+ - Organization: `fml-inc`
344
+ - Repository: `fml`
345
+ - Workflow: `publish-fml-cli.yml`
346
+ - Environment: `npm`
347
+ - Allowed action: `npm publish`
348
+
349
+ The GitHub `npm` environment should allow only `fml-v*` tags and may require a
350
+ reviewer. The publish job has no npm token, source checkout, dependency
351
+ installation, or build step; it receives only the smoke-tested tarball and its
352
+ checksum. npm provenance is disabled because the source repository is private,
353
+ while OIDC trusted publishing remains enabled.
354
+
109
355
  ## License
110
356
 
111
357
  Proprietary — see [LICENSE](LICENSE).
@@ -0,0 +1,180 @@
1
+ ---
2
+ name: fml
3
+ description: Route explicit FML requests to FML MCP tools, CLI operations, or the built-in branch and pull-request review workflow. Use when the user invokes /fml or $fml, explicitly asks to use FML, requests an FML command or tool, or asks for `fml review`. The `review` route is an agent workflow, never an `fml review` CLI command.
4
+ ---
5
+
6
+ <!-- fml-managed-agent-surface:v1 -->
7
+
8
+ # FML Agent Router
9
+
10
+ Use this skill as FML's agent-native command surface. Route a request to an
11
+ FML MCP tool, an actual `fml` CLI command, or an agent workflow defined here.
12
+
13
+ ## Invocation contract
14
+
15
+ Use the user text that activated this skill. Different hosts may preserve
16
+ trailing text in the original prompt, append an arguments annotation, or
17
+ deliver it immediately after activation. Treat that accompanying text as
18
+ `<command> [args...]`; do not depend on one host's invocation syntax or
19
+ argument-substitution behavior.
20
+
21
+ For an explicit skill invocation, parse the first trailing token as the
22
+ subcommand. For a natural-language invocation, infer a subcommand only from
23
+ the user's explicit FML request. With no subcommand, show concise help and do
24
+ not run a command merely to fill the response.
25
+
26
+ ## Routing rules
27
+
28
+ 1. Select `review` before doing CLI or MCP discovery. If the subcommand is
29
+ `review`, or the user explicitly asks for the FML review workflow, perform
30
+ the complete review workflow below in this agent session. `review` is not
31
+ an FML CLI subcommand. Never execute `fml review` or delegate the workflow
32
+ to the CLI.
33
+ 2. For structured read-only data, prefer a dedicated FML MCP tool when one is
34
+ available. Prefer the CLI for install, authentication, lifecycle, observer,
35
+ environment, and sync operations.
36
+ 3. If command coverage is unclear, run `fml commands`. For backend tools, run
37
+ `fml tools list --json` and `fml tools describe <name> --json`; do not guess
38
+ tool names or argument schemas.
39
+ 4. FML activity and history commands read data synced to the selected FML
40
+ organization. If the user explicitly asks for unsynced, machine-local
41
+ session data, explain that this command surface does not expose a local
42
+ analytics database.
43
+ 5. Apply the host's normal approval and safety rules to writes and destructive
44
+ actions. Never silently run `sync reset`, `uninstall --purge`, integration
45
+ writes, automation mutations, memory writes or deletes, or analysis runs.
46
+ 6. Summarize large structured results unless the user asks for raw output.
47
+
48
+ ## Common routes
49
+
50
+ - `review`: follow the complete pull-request review workflow below in the
51
+ current agent session.
52
+ - Install, auth, environment, observer, lifecycle, or sync: use the CLI command
53
+ discovered through `fml commands` or command help.
54
+ - Read-only activity, history, spending, configuration, integration, or
55
+ provenance: use the matching FML MCP tool by its live description, with a
56
+ CLI fallback when available.
57
+ - Backend tool list, description, or invocation: use `fml tools ...` and
58
+ describe unfamiliar tools before calling them.
59
+ - Automations, memory, analysis runs, integration writes, or other mutations:
60
+ discover the live schema, explain the change, and obtain any required
61
+ approval before invoking it.
62
+
63
+ If the preferred route is unavailable, use the listed fallback and say which
64
+ fallback was used.
65
+
66
+ ## CLI discovery
67
+
68
+ Use runtime discovery instead of relying on a static command inventory:
69
+
70
+ ```bash
71
+ fml commands
72
+ fml tools list --json
73
+ fml tools list --category integrations --json
74
+ fml tools describe <name> --json
75
+ fml tools call <name> --args '<json>'
76
+ fml tools call <name> --file <path>
77
+ ```
78
+
79
+ Prefer `--file` for multiline or nested JSON. Run `fml <command> --help` before
80
+ using an unfamiliar bespoke command.
81
+
82
+ ## Authentication and failures
83
+
84
+ - Use `fml doctor` to diagnose authentication, organization, observer, sync,
85
+ environment, and API connectivity.
86
+ - Use `fml login --device` when an interactive browser callback is unavailable.
87
+ - Never print or copy credential-store files or token values.
88
+ - Report the failed command and the relevant error. Do not retry indefinitely.
89
+
90
+ ## Pull-request review workflow
91
+
92
+ Apply this entire section for the `review` route.
93
+
94
+ ### 1. Establish the review scope
95
+
96
+ 1. Read repository instructions that govern the changed files.
97
+ 2. Determine the current branch and base ref. Prefer an explicitly supplied
98
+ base or PR base. Otherwise use the remote default from
99
+ `refs/remotes/origin/HEAD`, then fall back to a local `main` or `master`.
100
+ Do not fetch or mutate branches solely to perform the review.
101
+ 3. Inspect the branch and working-tree scope separately:
102
+
103
+ ```bash
104
+ git status --short
105
+ git diff --stat <base>...HEAD
106
+ git diff --find-renames <base>...HEAD
107
+ git log --oneline --decorate <base>..HEAD
108
+ git diff
109
+ git diff --cached
110
+ ```
111
+
112
+ 4. Read complete changed files and relevant callers, tests, schemas, or
113
+ configuration when the diff alone is insufficient.
114
+
115
+ State the chosen base and whether uncommitted changes are included. If no
116
+ reliable base can be determined, ask the user rather than inventing one.
117
+
118
+ ### 2. Review the code
119
+
120
+ Prioritize defects that could affect users or maintainers:
121
+
122
+ - correctness, edge cases, and error handling
123
+ - security, authorization, privacy, and secret handling
124
+ - data loss, unsafe migrations, and irreversible operations
125
+ - concurrency, retries, idempotency, and partial failure
126
+ - compatibility across supported platforms and agent targets
127
+ - public contracts, packaging, install/uninstall symmetry, and upgrade paths
128
+ - missing tests for meaningful behavior or regression risk
129
+
130
+ Do not report formatting preferences or speculative concerns as defects. Trace
131
+ the actual execution path and cite the smallest useful file and line location.
132
+ Each finding must explain the triggering conditions, concrete impact, and a
133
+ practical repair direction.
134
+
135
+ ### 3. Use FML context only for unresolved intent
136
+
137
+ Finish the code-based review before consulting FML. If a finding or design
138
+ question remains ambiguous, use read-only FML context:
139
+
140
+ - `fml_commit_context` for branch commits
141
+ - `fml_path_history` for the history of a changed path
142
+ - `fml_pr_context` when the pull-request number is known
143
+ - `search_engineering_sessions`, followed by `get_session_timeline`, for
144
+ relevant synced implementation sessions
145
+
146
+ CLI fallbacks are `fml search`, `fml sessions`, and `fml timeline`. If FML is
147
+ unavailable, unauthenticated, or has no matching data, note that briefly and
148
+ complete the review from repository evidence. Never use historical intent to
149
+ excuse a concrete defect in the current code.
150
+
151
+ Put any material provenance answer after the verdict under
152
+ `Follow-up: FML-sourced intent`, clearly separated from the findings.
153
+
154
+ ### 4. Report
155
+
156
+ Lead with findings, ordered by severity:
157
+
158
+ ```text
159
+ Findings
160
+
161
+ - [P1] Short imperative title — path/to/file.ts:42
162
+ Explain the triggering scenario, impact, and repair direction.
163
+
164
+ Questions / assumptions
165
+
166
+ - Only questions that materially affect the review.
167
+
168
+ Verdict
169
+
170
+ Request changes | Approve with comments | Approve
171
+
172
+ Follow-up: FML-sourced intent
173
+
174
+ - Include only if FML resolved a lingering question.
175
+ ```
176
+
177
+ Use `P0` for release-blocking or catastrophic risk, `P1` for serious defects,
178
+ `P2` for normal correctness or maintainability defects, and `P3` sparingly for
179
+ minor actionable issues. If there are no findings, say so explicitly and call
180
+ out any meaningful test or evidence gap in the verdict.
package/bin/fml CHANGED
@@ -1,20 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- // Suppress Node's experimental SQLite warning (emitted by node:sqlite, pulled in
4
- // transitively via @fml-inc/panopticon) before the dynamic import below loads it.
5
- // Scoped to the SQLite warning so other ExperimentalWarnings still surface.
6
- const originalEmit = process.emit;
7
- process.emit = function (name, data, ...args) {
8
- if (
9
- name === "warning" &&
10
- data &&
11
- data.name === "ExperimentalWarning" &&
12
- typeof data.message === "string" &&
13
- data.message.includes("SQLite")
14
- ) {
15
- return false;
16
- }
17
- return originalEmit.call(this, name, data, ...args);
18
- };
19
-
20
- import("../dist/cli.js");
3
+ import("../dist/cli.js").catch((error) => {
4
+ console.error(error);
5
+ process.exitCode = 1;
6
+ });
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+
3
+ import("../dist/hook-handler.js").catch(() => {
4
+ // Hook capture is strictly fail-open, including a broken package install.
5
+ process.exitCode = 0;
6
+ process.stdout.write("{}");
7
+ });