Commit graph

147 commits

Author SHA1 Message Date
Bryan Helmkamp
3f04e978c8 use Freeform question type for human gates with no fixed choices
When a human gate has only a freeform edge and no fixed choices, use
QuestionType::Freeform instead of MultipleChoice. This sends the user
directly to a text input prompt, skipping the unnecessary select menu.
Also removes the Quit choice from the REPL workflow so it uses the new
freeform-only path.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 12:25:37 -04:00
Bryan Helmkamp
c5bee7bf43 show prior node output before human gate prompts
Thread the previous stage's response through `Question.context_display`
so `ConsoleInterviewer` renders it before the interactive prompt. This
lets users see the agent's response before deciding what to do next in
looping workflows like REPL.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 11:57:35 -04:00
Bryan Helmkamp
1ddcb92ab7 add Fabro branding to generated commits and PRs
Update default git author to Fabro <noreply@fabro.sh>. Append
"Generated with Fabro" footer to all checkpoint and metadata commits,
and to PR bodies. When the commit author is overridden, add a
Co-Authored-By trailer for attribution.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 10:28:06 -04:00
Bryan Helmkamp
463ff8acd2 rename project_docs module to memory
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 10:02:11 -04:00
Bryan Helmkamp
e968ece42c rename git trailers from Arc-* to Fabro-* to match product rename
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 09:56:59 -04:00
Bryan Helmkamp
d37fb9a9b4 simplify model stylesheet: rename llm_model/llm_provider, add provider inference
Rename `llm_model` → `model` and `llm_provider` → `provider` in stylesheet
properties, accessor methods, and all DOT/doc references. Add
ProviderInferenceTransform that automatically infers provider from the model
catalog, eliminating redundant provider declarations in stylesheets.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 22:27:18 -04:00
Bryan Helmkamp
48eb867ce2 fix clippy large_enum_variant and rename ARC_ env vars in .env.example
Box the Usage field in Turn::Assistant to satisfy clippy::large_enum_variant.
Rename ARC_ prefixed env vars to FABRO_ in .env.example.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 14:37:22 -04:00
Bryan Helmkamp
28884ae093 rename Arc to Fabro in all Rust crates, symbols, env vars, and supporting files
- Rename 20 crate directories lib/crates/arc-* → fabro-*
- Update all Cargo.toml: crate names, dep paths, feature flags, bin name
- Rename arc_server module → fabro_server in fabro-llm
- ArcError → FabroError across 30+ files
- ARC_VERSION/ARC_GIT_SHA/ARC_BUILD_DATE → FABRO_* constants
- All use/qualified paths: arc_agent:: → fabro_agent::, etc. (~1500 occurrences)
- Env vars ARC_* → FABRO_* in string literals and shell scripts
- String literals: X-Arc-Demo, arc-bot, arc@local, arc-web, arc-mcp, etc.
- Path strings: .arc/ → .fabro/, arc.toml → fabro.toml, refs/arc/ → refs/fabro/
- arc-api.yaml → fabro-api.yaml (OpenAPI spec)
- skills/arc-create-workflow → fabro-create-workflow
- trycmd fixtures: $ arc → $ fabro
- Inline snapshots (insta) updated
- CI, Docker, install.sh, scripts, CLAUDE.md, AGENTS.md
- TypeScript app: env vars, headers, JWT issuer
- Docs: page slugs, git refs, config paths, sandbox names, repo URLs
- Repo references: brynary/arc → fabro-sh/fabro

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 12:25:58 -04:00
Bryan Helmkamp
3ce976a006 docs: update license references from AGPL to MIT
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 11:14:37 -04:00
Bryan Helmkamp
3a6ec9b9ef Rename Arc to Fabro in TypeScript/JavaScript
Rename directories (arc-web → fabro-web, arc-api-client → fabro-api-client),
update package names, import paths, TS-only identifiers (theme key, session
cookie, demo cookie, OAuth state, db filename, mock data), and supporting
files (Dockerfile, docker-compose, entrypoint, CI workflow, CLAUDE.md).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 11:13:18 -04:00
Bryan Helmkamp
d657025de0 feat(arc-ssh): add preview_url_base to SshConfig for port preview URLs
Allows users to specify a reachable base URL for SSH hosts so that
get_preview_url(port) returns the correct external URL instead of
falling back to localhost.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-12 08:10:32 -04:00
Bryan Helmkamp
c3f2ccd68a Update docs screenshots and fix demo workflow serialization
Replace docs/images screenshots (runs-board, run-detail, workflow-example)
with fresh captures from the current FABRO-branded UI in demo mode.

Also fix a panic in arc-api demo::run_config_to_api where None-valued
HashMap fields (e.g. sandbox.env) serialized to JSON null, which failed
to deserialize into non-optional HashMap fields in RunConfiguration.
Added strip_nulls helper to clean the intermediate JSON value.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-12 00:38:19 -04:00
Bryan Helmkamp
e7b8b3c938 refactor(arc-github): store client on GitHubTracker, drop redundant graphql_url field
- Add `client: reqwest::Client` field (matches LinearTracker pattern); eliminates 7 per-call client constructions that prevented connection pool reuse
- Remove `graphql_url: String` field — always derivable from base_url, computed via `graphql_url()` method at each call site
- Extract `make_test_issue()` test helper to replace 3 copy-pasted Issue struct literals

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 23:58:37 -04:00
Bryan Helmkamp
111b730eef feat(tracker): add Tracker trait with Linear and GitHub Projects V2 impls
- New arc-tracker crate defines the Tracker trait and shared Issue/BlockerRef types
- arc-linear: replace Issue/BlockerRef with arc-tracker re-exports, add LinearTracker struct implementing Tracker, remove free functions
- arc-github: add GitHubTracker implementing Tracker via Projects V2 GraphQL API, with lazy project node ID resolution (org → user fallback) and create_installation_access_token_for_projects helper
- 47 tests in arc-github (15 new), 24 tests in arc-linear (updated to use LinearTracker)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 23:32:03 -04:00
Bryan Helmkamp
10f7316f28 Simplify arc-linear: extract helper, fix O(n^2) ordering, add tracing
- Make execute_graphql private (callers use domain functions)
- Extract extract_issues() helper to deduplicate node-parsing blocks
- Replace O(n^2) .find() loop with HashMap for ID-ordered results
- Add tracing::debug on all public functions, warn on HTTP errors
- Extract BLOCKS_RELATION_TYPE constant for magic string

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-11 22:39:11 -04:00
Bryan Helmkamp
b509277e15 Add arc-linear crate for Linear issue tracker API integration
GraphQL client with 6 public functions: execute_graphql, fetch_viewer_id,
create_comment, update_issue_state, fetch_candidate_issues, and
fetch_issues_by_ids. Includes Issue/BlockerRef domain types with manual
normalization from GraphQL JSON responses.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-11 22:36:33 -04:00
Bryan Helmkamp
199691a949 Remove duplicate origin_url inherent method from SshSandbox
The inherent method shadowed the identical Sandbox trait method,
creating a risk of subtle divergence if one were changed without
the other.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-11 22:33:15 -04:00
Bryan Helmkamp
e0b3c4cde4 Add SSH sandbox provider (arc-ssh) for user-provided hosts
Adds a generic SSH sandbox that connects to any user-provided host via
openssh, without VM lifecycle management. Supports git clone with GitHub
App credentials, configurable working directory, and arc cp reconnection.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-11 22:29:51 -04:00
Bryan Helmkamp
2ce89e5e5e Simplify compaction code: extract helper method, named constant, avoid cloning
Extract duplicated compaction check+trigger blocks in the session loop into
Session::compact_if_needed(). Replace the hardcoded 20_000 token budget with
COMPACTION_USER_MESSAGE_TOKEN_BUDGET constant. Change extract_recent_user_messages
to take ownership of discarded turns instead of borrowing and cloning.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-11 22:13:29 -04:00
Bryan Helmkamp
f459aa78d7 Improve compaction quality with handoff framing, pre-turn check, and user message preservation
Reframe the summarization prompt as creating a handoff for a different assistant
(rather than self-summarization) to produce more thorough, explicit summaries.
Add a pre-turn compaction check so context is trimmed before building the LLM
request, not just after. Extract recent user messages from discarded turns during
compaction so the model retains the user's actual words alongside tool call/result
pairs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-11 22:09:23 -04:00
Bryan Helmkamp
e38d3ea3ce Add tracing to DaytonaSandbox::exec_command to diagnose stall watchdog timeouts
A workflow run hung for 33 minutes in a Daytona shell command despite
a 5-minute client-side timeout in tokio::select!. The root cause is
unknown — tests confirm the select pattern works correctly. Adding
info-level tracing at method entry (with command and timeout_ms),
after process service acquisition, and in each select arm so the
next occurrence reveals exactly where execution stalls.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-11 17:04:17 -04:00
Bryan Helmkamp
87435aef11 Preserve ts, run_id, event field order in progress.jsonl
Enable serde_json's preserve_order feature so Map uses insertion-order
IndexMap instead of sorted BTreeMap. Extract build_event_envelope()
from the on_event closure to deduplicate the envelope construction.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-11 13:01:17 -04:00
Bryan Helmkamp
55917f4005 Add arc graph subcommand to render workflow DOT graphs as SVG/PNG
Mirrors `arc validate` workflow resolution. Shells out to `dot` (graphviz)
with friendly error if not installed. Supports --format svg|png and -o output path.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-11 10:34:23 -04:00
Bryan Helmkamp
7dfbd53797 Print resolved graph path in arc run and arc validate
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-11 10:03:34 -04:00
Bryan Helmkamp
53b27ab188 Group arc doctor checks into Required / Optional / Server sections
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-11 09:59:54 -04:00
Bryan Helmkamp
ee58694cf0 Add tool call progress display to retro step
Wire ProgressUI and EventEmitter into the retro agent so it shows
stage spinners with nested tool calls, matching the look of agent
nodes in the main workflow.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-11 09:53:40 -04:00
Bryan Helmkamp
c475b0a25e Add warning when no git remote is configured during arc init
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-11 09:40:50 -04:00
Bryan Helmkamp
cd70962bd9 Add AbortReason to AgentError::Aborted for diagnosable abort messages
Previously, AgentError::Aborted was a bare variant that displayed as
just "Aborted", making it impossible to tell whether a session was
killed by wall clock timeout, user cancellation, or something else.
Now it carries an AbortReason (WallClockTimeout or Cancelled) so
terminal output like the retro agent failure message includes the cause.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-11 09:34:52 -04:00
Bryan Helmkamp
83ed0d42a4 Add spinner to arc doctor for immediate feedback
The command takes several seconds (especially with live probes) but
previously showed no output until fully complete. Now a braille spinner
animates while checks run.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-11 09:15:56 -04:00
Bryan Helmkamp
0af7a32794 Increase retro agent limits: 20 tool rounds, 3 minute timeout
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-11 09:12:37 -04:00
Bryan Helmkamp
30d1a11ace Add arc skill install subcommand to extract built-in skills to filesystem
Embeds the arc-create-workflow skill files via include_str! and installs them
to user (~/.claude/skills/ or ~/.agents/skills/) or project-level directories.
Supports --dir (claude|agents), --for (user|project), and --force flags.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-11 08:56:44 -04:00
Bryan Helmkamp
cfd7ea8c97 Update changelog and docs for installer, devcontainers, arc pr, and preflight improvements
Regenerate 2026-03-10 changelog with full commit set (installer, devcontainer
support, arc pr subcommands, --no-dotenv removal). Add 2026-03-11 changelog
for shadow branch run records and arc diff improvements. Update docs: CLI
reference (arc pr list/view/merge/close, --shortstat), devcontainers page
(replace placeholder with full content), run-configuration (devcontainer
field), checkpoints (per-node files on metadata branch), models catalog
(gemini-3.1-pro-preview-customtools). Improve preflight to show per-model
LLM checks instead of a single merged provider line.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-11 08:33:04 -04:00
Bryan Helmkamp
35b6282e6d Add gemini-3.1-pro-preview-customtools to model catalog
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-11 08:05:00 -04:00
Bryan Helmkamp
fe8493e6f9 Skip local worktree creation for remote sandbox runs
Remote sandboxes (Daytona, Exe) clone into their own environment, so
creating a local git worktree is unnecessary. The worktree decision
previously only checked worktree_mode and git_clean, ignoring the
sandbox provider entirely.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-11 07:52:39 -04:00
Bryan Helmkamp
d3df81c062 Add last_file_touched as third status extraction fallback
When workflow prompts tell agents to write results to a file with
embedded JSON status fields, the engine now falls back to reading the
last file the agent wrote if neither the response text nor status.json
contain extractable status fields.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-11 00:54:24 -04:00
Bryan Helmkamp
0bdb8e93b1 Add per-node files and run-level metadata to shadow branch
Store execution trace data (prompts, responses, status, diffs, etc.) on
the shadow branch alongside checkpoint/manifest data. This makes the
shadow branch a complete, self-contained record of each run.

- scan_node_files() scans nodes/ for allowlisted files (<512KB)
- Checkpoint commits now include per-node files
- init_run includes sandbox.json
- Finalize commit after workflow writes retro.json + final node files

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-11 00:37:52 -04:00
Bryan Helmkamp
a2288b7598 Simplify shorten_path and format call in progress UI
Use std::path::Path::strip_prefix instead of manual string manipulation,
and simplify redundant format! wrapper.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-11 00:28:33 -04:00
Bryan Helmkamp
72b96b1864 Add --shortstat flag to arc diff for compact summary output
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-11 00:28:01 -04:00
Bryan Helmkamp
eff2c472ec Render parallel fan-out branches like subagent info lines
Change parallel branch entries from tool-call style (6-space indent,
spinner) to subagent info style (8-space indent, ▸ prefix, dim/static
while running). Keeps ✓/✗ glyphs on completion.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-11 00:20:12 -04:00
Bryan Helmkamp
5301642b63 Include uncommitted changes in arc diff for in-progress runs
Drop `HEAD` from the live diff command so `git diff {base_sha}` compares
against the working tree instead of only committed changes. Extracts
`build_live_diff_cmd` for testability.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-11 00:16:30 -04:00
Bryan Helmkamp
d11d2c3c3b Show tool call paths relative to sandbox working directory
Tool output previously showed absolute sandbox paths (e.g.
write_file(/home/daytona/workspace/output/js/physics.js)) because
shorten_path() only checked the host CWD. Now ProgressUI stores the
sandbox working directory and strips it from displayed paths, producing
cleaner output like write_file(output/js/physics.js).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-11 00:13:58 -04:00
Bryan Helmkamp
2dadd49605 Revert "Fix verbose mode breaking terminal rendering after many tool calls"
This reverts commit f27a5e187a.
2026-03-10 23:19:27 -04:00
Bryan Helmkamp
9245a9987b Fix Daytona sandbox clone failing on unpushed worktree branch
When `arc run` uses a Daytona sandbox, `initialize()` re-detects the
branch from cwd — but by that point the worktree has switched HEAD to
`arc/run/{run_id}`, which was never pushed, causing the clone to fail
with HTTP 400. Pass the already-known base branch (e.g. `main`) from
the caller instead of re-detecting it inside the sandbox.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-10 23:11:42 -04:00
Bryan Helmkamp
ecb585d2a4 Clean up devcontainer bridge: inline trivial wrappers, fix initializeCommand bugs
- Remove `devcontainer_env()` and `resolve_devcontainer()` trivial wrappers,
  inline at call sites
- Fix initializeCommand Args quoting: use shlex::try_quote instead of naive join
- Fix initializeCommand silently dropping Parallel commands: now executes them
- Convert three repetitive lifecycle calls to a data-driven loop
- Use crate::millis_u64() in setup command loop for consistency

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-10 23:06:33 -04:00
Bryan Helmkamp
e8067740f7 Wire arc-devcontainer into sandbox creation flow
When `devcontainer = true` in TOML sandbox config, Arc now resolves
devcontainer.json from the repo, uses its Dockerfile for the Daytona
snapshot, runs lifecycle hooks (on_create, post_create, post_start)
in the sandbox, and merges devcontainer env vars under TOML env.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-10 22:54:59 -04:00
Bryan Helmkamp
e248fc5651 Migrate 29 CLI tests from assert_cmd/insta to declarative trycmd
Model list tests (6): exact stdout snapshots in .trycmd files, replacing
insta .snap files. Error validation tests (5): TOML with stderr-to-stdout
checking specific error messages. Doctor tests (3): TOML with env.inherit
= false for env_clear(). Validate tests (7): TOML with fs.cwd/sandbox for
file path access. Dry-run tests (6): TOML with fs.cwd/sandbox. Exec help
and no-prompt tests (2): TOML with env config.

Remaining in cli.rs: negative-assertion tests, file-system side-effect
test, tmpdir+env test, and 11 ignored API-key-dependent tests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-10 22:42:24 -04:00
Bryan Helmkamp
bf807686f6 Fix "Git clean: false" for remote sandboxes by checking clean + pushed
Remote sandboxes clone from origin, so "clean" should mean no uncommitted
changes AND the local branch is pushed. Replaces the hardcoded `false` with
a new `ensure_clean_and_pushed` that reuses `ensure_clean` + `branch_needs_push`.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-10 22:35:08 -04:00
Bryan Helmkamp
11c17bffab Add CLI telemetry event tracking with command sanitization and git hashing
Activate the dormant Segment-based telemetry infrastructure by wiring
lifecycle events in main.rs. Each CLI invocation now emits a "Command Run"
or "Command Error" event with sanitized args, duration, hashed repo
identifier, and CI detection.

- Add sanitize.rs: redacts sensitive CLI args (paths, values) while
  keeping flags, booleans, and numeric patterns
- Add git.rs: MD5-hashes normalized origin remote URL so HTTPS/SSH
  variants produce the same identifier
- Extend command_name to include nested subcommands (e.g. "pr create",
  "llm prompt", "system prune", "model list")
- Restructure main/main_inner to capture timing and return command name
  alongside result for telemetry

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-10 22:32:54 -04:00
Bryan Helmkamp
b864c1fa94 Add trycmd --help tests for each visible CLI subcommand
Covers run, validate, cp, preview, ssh, model, doctor, init, install,
pr, and system. Each test verifies --help exits 0 and produces output.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-10 22:10:28 -04:00
Bryan Helmkamp
1b4c6cb903 Detect unsupported COPY/ADD in devcontainer base Dockerfiles
Daytona's Rust SDK doesn't support uploading build context files, so
COPY/ADD instructions referencing local files fail at build time with
confusing errors. Detect this early in resolve() and return a clear
UnsupportedCopyAdd error. Multi-stage COPY --from= and ADD http(s)://
are still allowed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-10 22:09:30 -04:00