Skip to content

chore(deps): Bump actions/checkout from 4 to 6 - #5

Merged
dylanneve1 merged 1 commit into
mainfrom
dependabot/github_actions/actions/checkout-6
Apr 3, 2026
Merged

chore(deps): Bump actions/checkout from 4 to 6#5
dylanneve1 merged 1 commit into
mainfrom
dependabot/github_actions/actions/checkout-6

Conversation

@dependabot

@dependabot dependabot Bot commented on behalf of github Apr 3, 2026

Copy link
Copy Markdown
Contributor

Bumps actions/checkout from 4 to 6.

Release notes

Sourced from actions/checkout's releases.

v6.0.0

What's Changed

Full Changelog: actions/checkout@v5.0.0...v6.0.0

v6-beta

What's Changed

Updated persist-credentials to store the credentials under $RUNNER_TEMP instead of directly in the local git config.

This requires a minimum Actions Runner version of v2.329.0 to access the persisted credentials for Docker container action scenarios.

v5.0.1

What's Changed

Full Changelog: actions/checkout@v5...v5.0.1

v5.0.0

What's Changed

⚠️ Minimum Compatible Runner Version

v2.327.1
Release Notes

Make sure your runner is updated to this version or newer to use this release.

Full Changelog: actions/checkout@v4...v5.0.0

v4.3.1

What's Changed

Full Changelog: actions/checkout@v4...v4.3.1

v4.3.0

What's Changed

... (truncated)

Changelog

Sourced from actions/checkout's changelog.

Changelog

v6.0.2

v6.0.1

v6.0.0

v5.0.1

v5.0.0

v4.3.1

v4.3.0

v4.2.2

v4.2.1

v4.2.0

v4.1.7

v4.1.6

... (truncated)

Commits

Dependabot compatibility score

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


Dependabot commands and options

You can trigger Dependabot actions by commenting on this PR:

  • @dependabot rebase will rebase this PR
  • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
  • @dependabot show <dependency name> ignore conditions will show all of the ignore conditions of the specified dependency
  • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)

Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](actions/checkout@v4...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
@dependabot @github

dependabot Bot commented on behalf of github Apr 3, 2026

Copy link
Copy Markdown
Contributor Author

Labels

The following labels could not be found: ci, dependencies. Please create them before Dependabot can add them to a pull request.

Please fix the above issues or remove invalid values from dependabot.yml.

@dependabot
dependabot Bot requested a review from dylanneve1 as a code owner April 3, 2026 14:08
@dylanneve1
dylanneve1 merged commit 866683f into main Apr 3, 2026
7 of 8 checks passed
@dependabot
dependabot Bot deleted the dependabot/github_actions/actions/checkout-6 branch April 3, 2026 14:11
dylanneve1 added a commit that referenced this pull request Apr 10, 2026
- Validate mcpServer.args elements are strings and reject empty command (#1)
- Shell-quote interpolated paths in dream bash commands (#2, #11)
- Replace CLI-based diary write with mempalace_diary_write MCP tool (#3)
- Make validation error message platform-agnostic (#4)
- Update mempalacePython comment for platform-dependent default (#5)
- Wrap mp.init() in Promise.race with 30s timeout (#6)
- Make init conditional on successful validation, pass actual config (#7)
- Move import mempalace check into validateConfig (#8)
- Replace execFileSync with async execFile in init() (#9)
- Document that registerPlugin does NOT call init (#10)
- Update dream prompt header from "4-stage" to "5-stage" (#12)
- Update getPluginMcpServers JSDoc to document mcpServer path (#13, #17)
- Add .min(1) to palacePath/pythonPath zod schemas (#14)
- Distinguish ENOENT/EACCES/EPERM from import failures in validation (#15)
- Fix test name from "logs warning" to match actual behavior (#16)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
dylanneve1 added a commit that referenced this pull request Apr 10, 2026
* feat: integrate mempalace as built-in plugin for long-term memory

Adds mempalace (Python MCP server) as a first-class memory system.
When enabled, the agent gets semantic search, knowledge graph, and
verbatim memory storage via ChromaDB β€” all local, zero API calls.

Key changes:
- Extend plugin system with `mcpServer` field for non-Node MCP servers
- Add `registerPlugin()` for built-in plugin registration
- Create mempalace plugin (factory pattern, validates python venv)
- Wire mempalace into dream mode (Stage 5: mine logs into palace)
- Add `mempalace` config schema (enabled, palacePath, pythonPath)
- Add default paths for palace dir and python venv binary

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor(dream): mine daily notes instead of raw logs, add diary writing

Dream Stage 5 now mines memory/daily/ (curated observations) instead of
raw logs/ directory, eliminating junk chunks (tool JSON, df output, etc).
Added personal diary writing instruction β€” agent reflects on feelings,
state of mind, learnings, and loose threads after each dream run.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: address PR #27 review comments

- plugin.ts: validate mcpServer.args entries are strings and reject empty command
- dream.ts: quote interpolated paths in shell commands, replace mcp_server CLI diary with direct file write
- mempalace/index.ts: platform-agnostic error message for missing python binary
- paths.ts: update comment to reflect platform-dependent venv path
- bootstrap.ts: wrap mempalace init in 30s timeout to match loadSinglePlugin behavior

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: restore mempalace CLI diary writer, keep path quoting

Copilot suggested removing the mcp_server CLI invocation for diary
writing but that's the intended mempalace interface. Restored it
with quoted paths.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* test: add gating/validation tests for mempalace integration

- plugin.ts: test rejection of empty mcpServer.command and non-string args elements
- dream.ts: test mempalace section gating β€” verify mining/diary instructions
  only appear when mempalace is configured, skip message when not
- 1306 tests passing (4 new)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: upgrade mempalace system prompt with comprehensive tool docs

Adapted from mempalace SKILL.md (v3.1.0). Key improvements:
- Session protocol (verify before responding, invalidate stale facts)
- Full tool documentation including kg_timeline, traverse, find_tunnels,
  diary_read/write, delete_drawer, graph_stats, check_duplicate
- Semantic search tips (meaning-based, not keyword)
- Knowledge graph temporal validity guidance
- Tests updated to verify all tool names appear in prompt

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: extract mempalace prompt to prompts/mempalace.md

Move system prompt instructions out of TypeScript into a .md file,
matching the pattern used by dream.md and other prompts. Plugin loads
and interpolates {{palacePath}} at runtime with graceful fallback.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: replace pixi.intel.com registry URLs in lockfile with npmjs.org

Lockfile had resolved URLs pointing to pixi.intel.com (private/corporate
registry) for @Anthropic-AI packages, causing CI to fail with ENOTFOUND.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: resolve all lint warnings and formatting issues

Remove unused imports, variables, and catch bindings across 14 files.
Add yield statements to generator function mocks. Fix prettier formatting.

0 lint warnings, 0 format issues, 1307 tests passing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: address all 17 Copilot review comments on PR #27

- Validate mcpServer.args elements are strings and reject empty command (#1)
- Shell-quote interpolated paths in dream bash commands (#2, #11)
- Replace CLI-based diary write with mempalace_diary_write MCP tool (#3)
- Make validation error message platform-agnostic (#4)
- Update mempalacePython comment for platform-dependent default (#5)
- Wrap mp.init() in Promise.race with 30s timeout (#6)
- Make init conditional on successful validation, pass actual config (#7)
- Move import mempalace check into validateConfig (#8)
- Replace execFileSync with async execFile in init() (#9)
- Document that registerPlugin does NOT call init (#10)
- Update dream prompt header from "4-stage" to "5-stage" (#12)
- Update getPluginMcpServers JSDoc to document mcpServer path (#13, #17)
- Add .min(1) to palacePath/pythonPath zod schemas (#14)
- Distinguish ENOENT/EACCES/EPERM from import failures in validation (#15)
- Fix test name from "logs warning" to match actual behavior (#16)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: add 'mempalace' to LogComponent type

TypeScript type check was failing because 'mempalace' wasn't in the
LogComponent union type used by log/logError/logWarn functions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: allow MCP tools in dream prompt when required by Stage 5

Update tool access statement to permit MCP tools for mempalace
mining stage instead of blanket-blocking all MCP tools.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: duplicate guard in registerPlugin, pass MCP servers to dream

- registerPlugin now checks for duplicates before setting env vars
  or logging success, preventing misleading logs and env clobbering
- Dream agent now receives mempalace MCP servers when configured,
  so Stage 5 diary/mining tools actually work

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add selective MCP server loading via 'only' filter

getPluginMcpServers now accepts an optional plugin name filter:
- omitted = all plugins (backwards compatible for chat sessions)
- [] = none
- ["mempalace"] = only mempalace

Dream mode uses ["mempalace"] to load only what it needs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: load mempalace prompt from dirs.prompts, fix dream systemPrompt

- Mempalace prompt now loads from ~/.talon/prompts/mempalace.md
  (user-customisable, seeded on first run) instead of relative to
  source file. Consistent with heartbeat/dream prompt loading.
- Dream systemPrompt now permits MemPalace MCP tools when configured,
  preventing conflict with the markdown prompt's Stage 5 instructions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: move duplicate check before validation, gate dream on plugin registration

- registerPlugin checks for duplicates before running validateConfig,
  avoiding expensive re-validation on accidental double registration
- Dream mempalace integration now gated on getPlugin("mempalace")
  instead of just config.mempalace.enabled, so failed validation
  or registration doesn't cause dream-time MCP tool failures

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(mempalace): correct CLI arg order for status check

The --palace flag is a global option that must come before the
subcommand. Wrong order caused the init health check to always
fail with exit 2, logging a misleading "not yet initialized" warning.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: address Copilot review round 8 β€” validation, error handling, unused param

- Validate `import mempalace.mcp_server` (actual spawned module) instead of
  just `import mempalace` in validateConfig
- Add timeout/killed error branching in validateConfig catch block
  (ETIMEDOUT, signal, killed) with specific messages instead of generic
  "not installed"
- Include stderr details in import failure messages for debugging
- Remove unused `config` from ProcessAndReplyParams and all processAndReply
  call sites (flushQueue, retry, callback handler)
- Replace `mempalace status` CLI smoke test in init() with a simple import
  check β€” fixes false "Palace not yet initialized" warning when palace IS
  initialized but CLI subcommand doesn't exist

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: remove config from message queue chain, fix pythonPath comment

- Remove config from queue entry type, enqueueMessage signature, and
  all 3 call sites β€” completes the cleanup started in round 8
- Eliminates unnecessary TalonConfig reference (including botToken) from
  queue state
- Update mempalace plugin header comment to document platform-dependent
  pythonPath default (bin/python on Unix, Scripts/python.exe on Windows)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
claudiusthebot pushed a commit that referenced this pull request May 12, 2026
… on terminal, etc.

Address 5 of the 6 Copilot review threads on PR #96. The 6th (mid-run
TriggerStatus rename) is a larger semantic refactor and deferred to a
later commit; this commit pairs the smallest reasonable fix at each
site with regression tests where they're cleanly testable.

1. src/core/triggers.ts:128 β€” log WriteStream missing error handler.
   createWriteStream() with no .on("error") emits an unhandled
   EventEmitter `error` event if the log file becomes unwritable
   (disk full, permission flip), which crashes the Node process. Added
   a logError-routing handler so disk-tier failures degrade gracefully
   without killing the supervisor.

2. src/storage/trigger-store.ts:60 β€” fireCount doc/semantics mismatch.
   The doc-comment claimed "Number of mid-run TALON_FIRE: lines" but
   the supervisor increments fireCount for every wake (mid-run and
   terminal). Fixed the comment to match the actual semantics; same
   counter, accurate meaning. Avoids breaking any caller that already
   relies on fireCount as a total.

3. src/core/triggers.ts:fireWake β€” mid-run prompt says "Status: fired"
   even when terminal=false, which can mislead downstream handling
   into treating an in-flight watcher as a completed run. Decoupled
   the prompt-display status from the on-disk TriggerStatus enum:
   non-terminal fires now show "Status: signalled" in both the header
   and the "Status:" line. Terminal fires unchanged.

4. src/core/triggers.ts:bufferAsPayload + fireWake β€” FIRE_PAYLOAD_MAX_BYTES
   truncation used String.prototype.slice (UTF-16 code units), so a
   payload of N multi-byte characters could exceed the documented byte
   cap and split a character mid-codepoint. Introduced truncateUtf8Tail/
   truncateUtf8Head helpers that encode to UTF-8 bytes, slice on a byte
   boundary, then walk over UTF-8 continuation bytes (10xxxxxx) so we
   never cut a multi-byte sequence in half. The byte cap is now actually
   enforced as bytes.

5. src/storage/trigger-store.ts:282 + supervisor β€” updateTrigger only
   marks the store dirty (10s autosave window). For terminal status
   transitions (errored/cancelled/timed_out/fired) a crash inside that
   window would leave on-disk status as "running", which loadTriggers()
   then misclassifies as "terminated by previous restart". Added
   persistNow() calls at the four supervisor transition sites:
   failTrigger, cancelTrigger, the hard-timeout handler, and the
   finalizeExit path. The on-disk store now always agrees with the
   in-memory state across terminal transitions.

6. src/core/gateway-actions.ts:trigger_create β€” always returned
   "Status: running" even when spawnTrigger() failed without throwing
   (unsupported language slipping past validation, child.pid undefined,
   failTrigger() routing). With #5 above, the store now reflects the
   real state synchronously, so we re-read getTrigger(id) after spawn
   and return ok:false + lastError when it landed in "errored", or
   surface the actual status string otherwise. Callers no longer get
   false success responses.

Regression tests (triggers-extended.test.ts):
- mid-run prompt asserts "Status: signalled" appears and "Status: fired"
  does NOT, on a still-running trigger. Covers fix #3.
- multi-byte UTF-8 payload (2000Γ— πŸ’§ = 8000 bytes vs 4000 string length)
  asserts the prompt's byte length stays bounded AND contains no
  Unicode replacement character (U+FFFD), which would indicate a
  mid-codepoint split. Covers fix #4.

The remaining Copilot thread (introducing a dedicated non-terminal
status enum value, replacing the TriggerStatus|"signalled" display-
status hack) is a wider type change with API/store implications;
better tackled in a follow-up than bundled into a defensive sweep.

Verification:
- npx vitest run β†’ 1747/1748 pass (the 1 failure is the pre-existing
  package.functional "Stopped" expectation that fails whenever a live
  Talon daemon is running on the host β€” same env-dependent failure
  noted in PR #144 and PR #90's verification blocks).
- npx vitest run src/__tests__/triggers* src/__tests__/trigger-store* β†’
  74/74 pass (35 in triggers-extended including 2 new, 22 in
  trigger-store, 17 in triggers).
- npx tsc --noEmit β†’ clean.
- npx prettier --check on all 4 changed files β†’ clean.
- npm run lint β†’ 0 errors in changed files (10 pre-existing warnings
  elsewhere unchanged).

πŸ€– Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
dylanneve1 pushed a commit that referenced this pull request May 13, 2026
… on terminal, etc.

Address 5 of the 6 Copilot review threads on PR #96. The 6th (mid-run
TriggerStatus rename) is a larger semantic refactor and deferred to a
later commit; this commit pairs the smallest reasonable fix at each
site with regression tests where they're cleanly testable.

1. src/core/triggers.ts:128 β€” log WriteStream missing error handler.
   createWriteStream() with no .on("error") emits an unhandled
   EventEmitter `error` event if the log file becomes unwritable
   (disk full, permission flip), which crashes the Node process. Added
   a logError-routing handler so disk-tier failures degrade gracefully
   without killing the supervisor.

2. src/storage/trigger-store.ts:60 β€” fireCount doc/semantics mismatch.
   The doc-comment claimed "Number of mid-run TALON_FIRE: lines" but
   the supervisor increments fireCount for every wake (mid-run and
   terminal). Fixed the comment to match the actual semantics; same
   counter, accurate meaning. Avoids breaking any caller that already
   relies on fireCount as a total.

3. src/core/triggers.ts:fireWake β€” mid-run prompt says "Status: fired"
   even when terminal=false, which can mislead downstream handling
   into treating an in-flight watcher as a completed run. Decoupled
   the prompt-display status from the on-disk TriggerStatus enum:
   non-terminal fires now show "Status: signalled" in both the header
   and the "Status:" line. Terminal fires unchanged.

4. src/core/triggers.ts:bufferAsPayload + fireWake β€” FIRE_PAYLOAD_MAX_BYTES
   truncation used String.prototype.slice (UTF-16 code units), so a
   payload of N multi-byte characters could exceed the documented byte
   cap and split a character mid-codepoint. Introduced truncateUtf8Tail/
   truncateUtf8Head helpers that encode to UTF-8 bytes, slice on a byte
   boundary, then walk over UTF-8 continuation bytes (10xxxxxx) so we
   never cut a multi-byte sequence in half. The byte cap is now actually
   enforced as bytes.

5. src/storage/trigger-store.ts:282 + supervisor β€” updateTrigger only
   marks the store dirty (10s autosave window). For terminal status
   transitions (errored/cancelled/timed_out/fired) a crash inside that
   window would leave on-disk status as "running", which loadTriggers()
   then misclassifies as "terminated by previous restart". Added
   persistNow() calls at the four supervisor transition sites:
   failTrigger, cancelTrigger, the hard-timeout handler, and the
   finalizeExit path. The on-disk store now always agrees with the
   in-memory state across terminal transitions.

6. src/core/gateway-actions.ts:trigger_create β€” always returned
   "Status: running" even when spawnTrigger() failed without throwing
   (unsupported language slipping past validation, child.pid undefined,
   failTrigger() routing). With #5 above, the store now reflects the
   real state synchronously, so we re-read getTrigger(id) after spawn
   and return ok:false + lastError when it landed in "errored", or
   surface the actual status string otherwise. Callers no longer get
   false success responses.

Regression tests (triggers-extended.test.ts):
- mid-run prompt asserts "Status: signalled" appears and "Status: fired"
  does NOT, on a still-running trigger. Covers fix #3.
- multi-byte UTF-8 payload (2000Γ— πŸ’§ = 8000 bytes vs 4000 string length)
  asserts the prompt's byte length stays bounded AND contains no
  Unicode replacement character (U+FFFD), which would indicate a
  mid-codepoint split. Covers fix #4.

The remaining Copilot thread (introducing a dedicated non-terminal
status enum value, replacing the TriggerStatus|"signalled" display-
status hack) is a wider type change with API/store implications;
better tackled in a follow-up than bundled into a defensive sweep.

Verification:
- npx vitest run β†’ 1747/1748 pass (the 1 failure is the pre-existing
  package.functional "Stopped" expectation that fails whenever a live
  Talon daemon is running on the host β€” same env-dependent failure
  noted in PR #144 and PR #90's verification blocks).
- npx vitest run src/__tests__/triggers* src/__tests__/trigger-store* β†’
  74/74 pass (35 in triggers-extended including 2 new, 22 in
  trigger-store, 17 in triggers).
- npx tsc --noEmit β†’ clean.
- npx prettier --check on all 4 changed files β†’ clean.
- npm run lint β†’ 0 errors in changed files (10 pre-existing warnings
  elsewhere unchanged).

πŸ€– Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
dylanneve1 pushed a commit that referenced this pull request May 13, 2026
* feat(triggers): self-authored watcher scripts that wake the bot

Triggers are bot-authored long-running scripts (bash / python / node)
that run as supervised subprocesses and signal back via stdout to fire
wake-up messages into the originating chat. Built for the case where a
fixed cron schedule doesn't fit β€” "wake me when this PR merges", "tell
me if BTC moves >5%", "watch this URL until it returns 200".

Contract:
  - Mid-run: a stdout line `TALON_FIRE: <text>` fires immediately and the
    script keeps running (multi-event watchers).
  - Exit 0: final fire with the tail of stdout/stderr as payload.
  - Exit non-zero: error fire with exit code + log tail.
  - Hard timeout (default 24h, max 7d): SIGTERM β†’ SIGKILL β†’ timed_out fire.

Tools exposed: trigger_create, trigger_list, trigger_cancel,
trigger_logs, trigger_delete. Per-chat cap of 5 active. Children are
killed on Talon shutdown β€” they do not survive a restart, and any
trigger left in running/pending on load is reaped to "terminated".

New modules:
  - src/storage/trigger-store.ts: persistence + validation
  - src/core/triggers.ts: supervisor (spawn, line buffers, fire dispatch)
  - src/core/tools/triggers.ts: 5 tool definitions
  - gateway-actions.ts: trigger_* bridge handlers
  - paths.ts: ~/.talon/data/trigger-runs/<chatId>/ for scripts and logs
  - bootstrap.ts: loadTriggers + initTriggers + resumeAfterRestart
  - index.ts: shutdownTriggers + flushTriggers in shutdown paths

Tests: 30 new (22 store + 8 supervisor including real-bash spawn
integration). 1397/1397 passing.

* style: auto-format with prettier

* test(triggers): branch coverage for python/node/idempotency/resumeAfterRestart/store

Adds targeted tests that bring branch coverage above the 60% global
threshold imposed by PR #121.  Exercises: commandForLanguage python &
node paths, spawnTrigger idempotency guard, cancelTrigger false-return,
resumeAfterRestart (no-deps / empty / matching / already-fired / old),
trigger-store unknown-id paths, FIRE_PAYLOAD_MAX_BYTES truncation, and
finalizeExit status-branch (cancelled exit + non-zero exit code).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* test(triggers): fix Windows path separator + add missing branch coverage

Two CI failures in the coverage-fix commit (9096518):

1. Windows N22 β€” trigger-store.test.ts: triggerScriptPath regex used Unix
   forward-slashes but resolve() returns backslashes on Windows. Fixed by
   normalising path separators before matching.

2. Ubuntu N22 β€” branch coverage 59.67% < 60% (threshold differs from N24
   due to V8 v11 vs v12 branch instrumentation). Added 4 more targeted tests
   in triggers-extended.test.ts:
   - trigger-store persistNow() path (lines 159-160)
   - readTriggerLogTail catch path via EISDIR (line 329)
   - readTriggerLogTail truncated:true path (line 327)
   - fireWakeUp dispatch-error catch path (line 394 of triggers.ts)

All 18 extended tests pass. typecheck βœ… Β· format:check βœ….

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* test(triggers): add N22 branch coverage for TALON_FIRE, empty-output, and store helpers

Ubuntu Node 22 (V8 v11) instruments more branches than Node 24 (V8 v12),
causing coverage to land at 59.67% on N22 while passing on N24.

Added 7 new tests to triggers-extended.test.ts:
- Empty stdout: covers fireWake's `trimmed ? ... : (no output)` false branch
- Mid-run TALON_FIRE: covers handleStdoutLine true branch + fireWake
  terminal=false ("signalled" header path)
- validateLanguage false paths: includes() false + typeof short-circuit
- sanitizeChatId with special chars: confirms replace() regex path
- languageExtension direct call: covers all 3 switch arms explicitly
- getTriggerByName returning undefined: covers find() undefined path

Also imports getTriggerByName, validateLanguage, sanitizeChatId, and
languageExtension from trigger-store for direct testing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* test(triggers): comprehensive branch coverage round 4 β€” target Node 22 CI pass

Add 15 new tests across 4 test files to cover previously-unreachable branches,
specifically the ones V8 v11 (Node 22) counts but were uncovered since hb #179:

trigger-store.test.ts (+9 tests):
- loadTriggers: file-not-present, non-object JSON, corrupt primary (3 variants)
- Backup parses as null (line 94 ternary false arm)
- save() catch: Error throw and non-Error string throw (both instanceof arms)
- readTriggerLogTail: non-Error throw (false arm of err instanceof Error)

triggers-extended.test.ts (+5 new describe blocks):
- fireWake with undefined payload (payload ?? '' false arm)
- fireCount undefined treated as 0 (fireCount ?? 0 false arm)
- finalizeExit with null exit code β€” signal kill (code ?? undefined false arm)
- handleStdoutLine with no lineBuffer entry (pushBufferLine if(!buf) true arm)
- shutdownTriggers when no children running (if(children.size===0) true arm)
- Child process error event handler (line 152 handler covered)
- Timeout timer fires after child already exited (if(!c) return true arm)

cleanup-registry.test.ts (+1 test):
- Handler throws a non-Error string (err instanceof Error false arm)

mcp-launcher.test.ts (+1 test):
- ensureLauncher throws when file does not exist (if(!existsSync) true arm)
  Uses vi.doMock to intercept node:fs before fresh module import.

Node 24 local result: 60.26% (2146/3561). Previous Node 22 CI: 59.73%.
1744 tests, all passing. tsc clean, prettier clean.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(triggers): 5 Copilot review fixes β€” byte-safe truncation, persist on terminal, etc.

Address 5 of the 6 Copilot review threads on PR #96. The 6th (mid-run
TriggerStatus rename) is a larger semantic refactor and deferred to a
later commit; this commit pairs the smallest reasonable fix at each
site with regression tests where they're cleanly testable.

1. src/core/triggers.ts:128 β€” log WriteStream missing error handler.
   createWriteStream() with no .on("error") emits an unhandled
   EventEmitter `error` event if the log file becomes unwritable
   (disk full, permission flip), which crashes the Node process. Added
   a logError-routing handler so disk-tier failures degrade gracefully
   without killing the supervisor.

2. src/storage/trigger-store.ts:60 β€” fireCount doc/semantics mismatch.
   The doc-comment claimed "Number of mid-run TALON_FIRE: lines" but
   the supervisor increments fireCount for every wake (mid-run and
   terminal). Fixed the comment to match the actual semantics; same
   counter, accurate meaning. Avoids breaking any caller that already
   relies on fireCount as a total.

3. src/core/triggers.ts:fireWake β€” mid-run prompt says "Status: fired"
   even when terminal=false, which can mislead downstream handling
   into treating an in-flight watcher as a completed run. Decoupled
   the prompt-display status from the on-disk TriggerStatus enum:
   non-terminal fires now show "Status: signalled" in both the header
   and the "Status:" line. Terminal fires unchanged.

4. src/core/triggers.ts:bufferAsPayload + fireWake β€” FIRE_PAYLOAD_MAX_BYTES
   truncation used String.prototype.slice (UTF-16 code units), so a
   payload of N multi-byte characters could exceed the documented byte
   cap and split a character mid-codepoint. Introduced truncateUtf8Tail/
   truncateUtf8Head helpers that encode to UTF-8 bytes, slice on a byte
   boundary, then walk over UTF-8 continuation bytes (10xxxxxx) so we
   never cut a multi-byte sequence in half. The byte cap is now actually
   enforced as bytes.

5. src/storage/trigger-store.ts:282 + supervisor β€” updateTrigger only
   marks the store dirty (10s autosave window). For terminal status
   transitions (errored/cancelled/timed_out/fired) a crash inside that
   window would leave on-disk status as "running", which loadTriggers()
   then misclassifies as "terminated by previous restart". Added
   persistNow() calls at the four supervisor transition sites:
   failTrigger, cancelTrigger, the hard-timeout handler, and the
   finalizeExit path. The on-disk store now always agrees with the
   in-memory state across terminal transitions.

6. src/core/gateway-actions.ts:trigger_create β€” always returned
   "Status: running" even when spawnTrigger() failed without throwing
   (unsupported language slipping past validation, child.pid undefined,
   failTrigger() routing). With #5 above, the store now reflects the
   real state synchronously, so we re-read getTrigger(id) after spawn
   and return ok:false + lastError when it landed in "errored", or
   surface the actual status string otherwise. Callers no longer get
   false success responses.

Regression tests (triggers-extended.test.ts):
- mid-run prompt asserts "Status: signalled" appears and "Status: fired"
  does NOT, on a still-running trigger. Covers fix #3.
- multi-byte UTF-8 payload (2000Γ— πŸ’§ = 8000 bytes vs 4000 string length)
  asserts the prompt's byte length stays bounded AND contains no
  Unicode replacement character (U+FFFD), which would indicate a
  mid-codepoint split. Covers fix #4.

The remaining Copilot thread (introducing a dedicated non-terminal
status enum value, replacing the TriggerStatus|"signalled" display-
status hack) is a wider type change with API/store implications;
better tackled in a follow-up than bundled into a defensive sweep.

Verification:
- npx vitest run β†’ 1747/1748 pass (the 1 failure is the pre-existing
  package.functional "Stopped" expectation that fails whenever a live
  Talon daemon is running on the host β€” same env-dependent failure
  noted in PR #144 and PR #90's verification blocks).
- npx vitest run src/__tests__/triggers* src/__tests__/trigger-store* β†’
  74/74 pass (35 in triggers-extended including 2 new, 22 in
  trigger-store, 17 in triggers).
- npx tsc --noEmit β†’ clean.
- npx prettier --check on all 4 changed files β†’ clean.
- npm run lint β†’ 0 errors in changed files (10 pre-existing warnings
  elsewhere unchanged).

πŸ€– Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: claudiusthebot <claudius@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant