47 Commits

Author SHA1 Message Date
EugeneTes
094d518827 fix(claude-code): disable built-in plugins and learn new ones from init
Claude Code 2.1.287 loads cc-plugin-* built-ins regardless of --setting-sources,
which tripped the fail-closed init check. Disable every known built-in in
--settings, and when init lists only built-ins that slipped through, disable them
process-wide and replay the request once. Other plugins still fail closed.
2026-10-02 10:08:23 +00:00
EugeneTes
d2fd7ffa02 feat(google-calendar): encrypt chat tokens and give watchers a short-lived access token
token.json is sealed with AES-256-GCM (key derived from the OAuth client secret,
bound to the chat), so the agent's processes can read the file but not the
refresh token. Plain files, including VolcanicSecretary's refresh_token format,
are rewritten sealed on first read.

The scheduler gains IScriptEnvironment: extra per-run variables set after the
process environment filter and redacted from the run's output. The Telegram
host uses it to pass GOOGLE_ACCESS_TOKEN, refreshed to cover the job's timeout;
the refresh token and client secret never reach the script.
2026-10-02 08:31:24 +00:00
EugeneTes
28bbfbc759 feat(scheduler): store jobs per chat and import VolcanicSecretary job files
Each chat's jobs live in <workspace>/.volcanic/scheduler/jobs.json. On start the
scheduler loads every chat's file, moves the retired shared
<agentDir>/scheduler/jobs.json into them and renames it .migrated-<ts>.
A VolcanicSecretary jobs.json (bare array) in a chat's folder is converted
in place for that chat; the original is kept as .secretary-<ts>.

Also adds the VolcanicSecretary data migration plan.
2026-10-02 07:29:48 +00:00
EugeneTes
8014a0e770 refactor(scheduler): drop the reminder job kind
Jobs are prompts or watchers. A reminder is a prompt the agent passes on, so
it lands in the transcript. Stored reminder jobs load as prompts
("Remind me: <text>"). Also records the Coolify deploy target in CLAUDE.md.
2026-09-29 09:30:40 +00:00
EugeneTes
c3a0cf234c feat(google-calendar): store each chat's token in its workspace
Tokens now live in <cwd>/.volcanic/google-calendar/token.json, as in the
VolcanicSecretary reference, instead of <agentDir>/google-calendar/<chat
key>/. GoogleCalendarOptions.TokenDirectory, when set, keeps the old
per-chat layout under that root. Spec, docs and CLAUDE.md updated.
2026-09-28 20:42:58 +02:00
EugeneTes
fd6b9027b6 fix(scheduler): address review findings
- JobScheduler: a stored job whose zone lookup throws no longer fails StartAsync; timer re-armed under the lock;
  a delivery cut off by shutdown isn't recorded (one-offs fire again after restart); CancelJobAsync in one step
- Schedules.ParseAt: ISO 8601 with a date only (no machine-clock date for a bare 09:00)
- core: a FollowUp prompt that loses the race to a starting run joins it as a follow-up, not steering
- Telegram: TimeZoneFor tolerates non-numeric targets; RunPromptAsync waits only when queued; one agent dir
- ScriptRunner: bad workspace paths are Failed, not exceptions; zone id helpers share TimeZoneIds.ToIana's rule
- tests: no wall-clock sleeps in scheduler tests; transcript-entry, disabled-scheduler and failing-prompt coverage
- docs: spec notes for the above; README row for the scheduler
2026-09-27 10:56:45 +02:00
EugeneTes
a0d886eef3 feat(scheduler): schedule tool and per-session SchedulerExtension 2026-09-27 10:23:10 +02:00
EugeneTes
4bf99dc57c feat(scheduler): JobScheduler on TimeProvider with watcher, reminder and prompt firing
Spec: a skipped one-off fires after the next start; the late note's placement and no-exit-code failure wording are pinned down; IsDeliverable is part of the watcher invariant and must not create a session; saves snapshot inside a serialising gate.
2026-09-27 10:20:22 +02:00
EugeneTes
51bc0cedf1 feat(scheduler): ScriptRunner through the process spawn policy
Spec: on Windows the command goes through Arguments like the bash tool, since cmd.exe doesn't parse ArgumentList quoting; the workspace is created if missing, and a timeout vs cancellation outcome is spelled out.
2026-09-27 10:14:33 +02:00
EugeneTes
1cc60267f9 feat(scheduler): atomic JSON job store
jobs.json is { "version": 1, "jobs": [...] } in VolcanicJson camelCase,
written to jobs.json.<pid>.tmp and moved into place through one semaphore.
A corrupt file is renamed jobs.json.corrupt-<timestamp> and loading starts
empty. Each entry is deserialised on its own, so an entry with an unknown
kind or a missing required field is dropped with a warning like any other
invalid job instead of setting the whole file aside.
2026-09-27 10:10:33 +02:00
EugeneTes
d699593458 feat(scheduler): extension project, job model, cron and at parsing, validation 2026-09-27 10:07:28 +02:00
EugeneTes
96a6a5518b feat(claude-code): pass the session time zone to claude -p as TZ 2026-09-27 10:03:25 +02:00
EugeneTes
6ab98a8155 fix(telegram): address review findings
- A speech or download timeout (TaskCanceledException nobody asked for) is a failure
  with the user notice, not a silent shutdown; OpenAiSpeechToText maps it to
  "the request timed out."; UpdateRouter only treats the caller's cancellation as shutdown.
- send: WorkspacePaths resolves the real path component by component (realpath),
  closing the directory-link-inside-target bypass; `.` reports a directory.
- Image documents are attached inline only when their magic bytes are JPEG/PNG/GIF/WebP,
  under the detected type.
- Audio goes to STT as an ASCII audio.<ext> name.
- MCP Browser section mentions send only when it is active.
- RunInOrderAsync takes a cancellation token; queued work is skipped once disposal gives up;
  SendReplyAsync stays private behind ReplyInOrderAsync.
- Speech HttpClient handler recycles pooled connections; BuiltInTools.Send();
  IExtensionHost.Channel is abstract; WorkspacePaths in its own file.
- Tests: timeouts, symlink chains (Linux), sniffing, channel delivery failures,
  queued-work cancellation, gated voice ordering. Spec and docs updated.
2026-09-26 22:35:20 +02:00
EugeneTes
0b28b9627d Merge branch 'feat/google-calendar' 2026-09-26 21:24:34 +02:00
EugeneTes
2a201f7d95 fix(mcp): address review findings
- redact /mcp output, and stderr lines as they arrive (log, errors, tail)
- take host servers by name: configuration binding sorts keys anyway
- dispose kills the tree only without an exit code and only if the pid's
  start time matches the spawn (no kill of a reused pid)
- idle timer generation guards stale callbacks; catalogue check runs in
  the background with a 10 s cap; shutdown stops servers concurrently
- stop resets a failed status; /mcp shows an exited process; ordinal names
- spec: ${workspace} in command, ordering, dispose and /mcp wording
2026-09-26 21:18:12 +02:00
EugeneTes
2c5d5dfcb4 feat(mcp): extension activation, prompt section, lifecycle and /mcp
Spec: /mcp shows no pid (the SDK doesn't expose it) and never shows env values; the prompt section follows the server's own tools; the built-in collision check covers inactive built-ins.
2026-09-26 20:49:21 +02:00
EugeneTes
83ad683bd1 feat(mcp): per-session server connection and MCP tools
McpServerConnection starts the session's server lazily through
PrepareProcessAsync, applies the call timeout, reports exits with the
stderr tail and restarts on the next call, stops when idle, and supports
StopAsync (reusable) and idempotent DisposeAsync. McpTool exposes a
catalogue entry as an ITool and maps results with McpResultMapper.

Spec change (§5, Decisions): ModelContextProtocol.Core 2.2.0 does not send
notifications/cancelled when a request's token fires (verified against the
fake server), so calls go out through SendRequestAsync with their own
request id and the connection sends notifications/cancelled itself on abort
and timeout. Also documents exit detection, StopAsync vs DisposeAsync and
JSON-RPC errors as ordinary error results, per the plan.
2026-09-26 20:44:15 +02:00
EugeneTes
ed026ac6c8 feat(mcp): process-wide tool catalogue discovery
McpProcess starts a server through the SDK stdio client under the startup
timeout and keeps a stderr tail for its errors. McpCatalogCache runs one shared
discovery per server config in a temp dir, with the environment from the process
spawn policy. It keeps successes for the process lifetime and failures for 60 s.

Deviation from the plan: the discovery process is disposed and its temp dir
deleted in the background, after the catalogue is returned. SDK 2.2 waits the
whole ShutdownTimeout (5 s) with stdin still open before it kills the process,
so an awaited dispose held every first activation for 5 s. A new test
(Discovery_returns_without_waiting_for_the_server_shutdown) covers this. Spec
section 3 gets the new GetAsync signature, the detached discovery and the
background cleanup. Section 5 now describes the SDK's shutdown order correctly.
2026-09-26 20:31:43 +02:00
EugeneTes
881e7f0be9 fix(google-calendar): address review findings
- log an unknown stored zone once even when the tool description reads it first
- serialise the flow's token write with /calendar_disconnect under the flow gate
- a cancelled or expired pending flow is cleared, not re-sent or shown
- chat keys anchor with \z so a trailing newline is hashed
- a timeMax date includes that whole day (spec updated)
- dispose the flow's CancellationTokenSource, drop ConnectFlow.Token, Begin is a plain write
- GoogleCalendarOptions.IsConfigured replaces the host's copy of the rule; StoredToken is internal
- test BotSetupService's menu through DI, tokens absent from tool results
- Telegram.Tests csproj reference placed as in telegram-message-context; ChatHost passes calendar by name
- docs: per-event timeZone, both config sources for /calendar_*
2026-09-26 20:30:56 +02:00
EugeneTes
da6068c5dc feat(mcp): map MCP tool results to core tool results
The truncation note follows the kept text after a single newline, as the built-in read/grep tools do (plan snippet updated).
2026-09-26 20:19:03 +02:00
EugeneTes
b30c71d30a feat(mcp): server launch plumbing and tool naming
Spec: the complete environment goes to the SDK with InheritEnvironmentVariables=false instead of nulls; the cache key also covers cwd and prefix.
2026-09-26 20:17:37 +02:00
EugeneTes
5b7d593427 feat(mcp): Playwright preset and server resolution
Spec: the preset defaults --browser to chromium and drops --user-data-dir with --isolated; source order and the send-less prompt line are spelled out.
2026-09-26 20:15:35 +02:00
EugeneTes
149b932ca1 feat(google-calendar): /calendar_status and /calendar_disconnect, per-chat isolation tests 2026-09-26 20:15:16 +02:00
EugeneTes
e6b09fef1e feat(mcp): extension project and configuration
McpOptions/McpServerConfig/PlaywrightOptions with ApplyEnvironment (PLAYWRIGHT_* variables, quote-aware ExtraArgs split) and Validate; ShellWords; mcpServers from the user settings.json. New project in the solution and referenced by the extension tests.
2026-09-26 20:13:50 +02:00
EugeneTes
59d404ed08 feat(google-calendar): /calendar_connect device flow with automatic polling 2026-09-26 20:13:36 +02:00
EugeneTes
c2048a822e feat(google-calendar): create, update and delete with recurring scope resolution
Spec §7: the reference's calendar.ts is not in this repository, so the error and reply texts are now listed in the spec.
2026-09-26 20:11:47 +02:00
EugeneTes
edcfa690bd feat(google-calendar): calendar tool read actions over Calendar v3 2026-09-26 20:09:53 +02:00
EugeneTes
a30a4e4d03 feat(google-calendar): calendar time rules and rendering
Offset date-times are normalised to full RFC 3339 (seconds, T separator)
before they are sent; the spec's time rules say so.
2026-09-26 20:08:10 +02:00
EugeneTes
8baa79f074 feat(google-calendar): per-chat connections with cached, single-flight token refresh
Spec §4: connections are keyed by the chat's token directory; For(settings, scope).
2026-09-26 20:06:00 +02:00
EugeneTes
ccfa3c1ade feat(google-calendar): OAuth device flow, refresh and revoke client
Spec §3: DeviceAuthorization/PollStatus shapes, Success carries the access token, 5xx without error is a transport error, RefreshAsync returns AccessToken, RevokeAsync returns the failure reason (null on success).
2026-09-26 20:03:09 +02:00
EugeneTes
199ad47f64 feat(google-calendar): extension project, options and per-chat token store
Adds the GoogleCalendar extension project (Abstractions only, Private=false), GoogleCalendarOptions with
env fallbacks and a secret-free ToString, GoogleCalendarException/Messages, ChatKeys (scope -> safe directory
name), StoredToken and GoogleTokenStore (atomic write, owner-only on Unix, reads never throw), and an empty
GoogleCalendarConnections stub for Task 3. The test project gains the extension reference and
Microsoft.Extensions.TimeProvider.Testing 10.9.0.
2026-09-26 20:01:18 +02:00
EugeneTes
bbece220c8 fix(claude-code): /claude-code-login reports the outcome of a login it joined 2026-09-25 17:54:20 +00:00
EugeneTes
f620b33771 fix(claude-code): send the login link and the code question as one message 2026-09-25 17:53:14 +00:00
EugeneTes
fb7be219e5 fix(claude-code): a late expiry after a completed login replays without a second login 2026-09-25 17:52:21 +00:00
EugeneTes
1aa9197d9c feat(claude-code): /claude-code-login command 2026-09-25 17:38:39 +00:00
EugeneTes
d43fa52e4a fix(claude-code): bound the login flow and cover the held-Start path 2026-09-25 17:32:41 +00:00
EugeneTes
f90bf862f4 feat(claude-code): pause an expired request, log in through the host UI and replay it 2026-09-25 17:25:43 +00:00
EugeneTes
521d391527 feat(claude-code): single-flight login coordinator 2026-09-25 17:11:15 +00:00
EugeneTes
aa859a0dcf feat(claude-code): headless claude auth login driver 2026-09-25 17:03:42 +00:00
EugeneTes
0c972480a8 feat(claude-code): classify an expired subscription session as login-required auth failure 2026-09-25 16:55:37 +00:00
EugeneTes
17ce025c57 feat(prompt): PERSONA.md and MEMORY.md in the system prompt; AGENTS.md or CLAUDE.md, not both 2026-09-25 16:36:49 +00:00
EugeneTes
2321906719 feat(claude-code): pinned claude-opus-5-5 model 2026-09-25 14:42:12 +00:00
EugeneTes
f9403aed77 feat(claude-code): provider extension and mcp proposal bridge 2026-09-25 13:14:58 +00:00
VolcanicAgenticCore
b66dd52cfc feat(anthropic): current model catalogue with adaptive thinking and summarized display 2026-09-25 12:49:35 +00:00
EugeneTes
3c0b84b392 feat(anthropic): messages api provider extension 2026-09-25 12:46:29 +00:00
EugeneTes
89623e14c2 feat(openai): chat completions provider extension
Streams POST {baseUrl}/chat/completions over SSE (System.Net.ServerSentEvents, no NuGet) and maps delta.content, delta.reasoning_content / delta.reasoning and delta.tool_calls onto AssistantMessageEvents via AssistantMessageBuilder. Configurable through OpenAIProviderOptions so one extension serves OpenAI, OpenRouter, Ollama and other compatible servers; ships the gpt-5 / gpt-5-mini / gpt-4.1 catalogue.
2026-09-25 12:45:43 +00:00
VolcanicAgenticCore
351bc0a2f6 chore: scaffold solution 2026-09-25 11:56:33 +00:00