Commit Graph

6 Commits

Author SHA1 Message Date
oldschoola a2854ba768 fix: migrate coding-agent tests from fs.rm to removeWithRetries
Migrate 203 test files (356 call sites) from fs.rm/fs.rmSync to
removeWithRetries/removeSyncWithRetries to reduce EBUSY test failures
on Windows. removeWithRetries is now exported from @oh-my-pi/pi-utils.

The migration uses a regex-based approach that:
- Replaces fs.rm(path, { recursive, force }) → removeWithRetries(path)
- Replaces fs.rmSync(path, { recursive, force }) → removeSyncWithRetries(path)
- Replaces fs.rm(path) → removeWithRetries(path) (no options)
- Skips fs.rm/fs.rmSync inside template literals (bun --eval scripts)
- Adds imports to existing @oh-my-pi/pi-utils import or creates new one
- Removes unused fs imports where fs.rm was the only fs usage (4 files)
2026-06-23 15:28:05 -07:00
Ogrodev 87da6d373f fix(coding-agent): scope managed skills to profiles 2026-06-14 20:49:05 -03:00
can1357 3efebf8805 fix: harden merged provider, agent-loop, eager, and autolearn paths
- agent-loop: raise repetition-detection floor to 180 chars and clear thinking
  replay anchors when collapsing a detected loop.
- providers/google: ignore empty text parts, retain terminal thoughtSignatures,
  and stop function-call signatures clobbering the prior block.
- autolearn: capture goal-mode at the turn boundary; harden managed-skill writes
  against hard-links/symlinks (O_NOFOLLOW + nlink); refuse minting managed skills
  whose name an authored skill already claims.
- eager tasks: thread agentKind through the session so a custom top-level agentId
  still gets always-mode delegation; split Eager Tasks prompt into hard vs soft.
- title-generator: race the online title model against a local tiny-model fallback.
- eager-todo: keep the soft reminder aligned with the todo init schema.
- mcp/stdio: keep close() detaching the read loop instead of awaiting it.
- stream loop: fix collapsing and tool-call thought-signature handling.
2026-06-14 17:09:59 +02:00
metaphorics 12c4078b4b fix(coding-agent): harden managed-skill writes (symlink root, empty content, races)
Grill findings on the auto-learn change-set:

- Reject a symlinked managed-skills ROOT (not just the per-skill dir): lstat on a
  child follows intermediate components, so a symlinked root would let an
  otherwise-valid name write/delete outside the isolated directory. Added
  `assertManagedRootSafe()` to create, update, and delete.
- Reject empty content: an all-whitespace/control description sanitizes to "" and
  the `requireDescription` discovery scan then silently drops the skill, so the
  tool would report success for a skill that never appears. Reject empty
  description/body before writing.
- Serialize create/update/delete on the same skill name (`serializeSkillMutation`):
  both tools are non-exclusive, so a parallel batch could interleave (e.g. update
  observing the file mid-delete). O_EXCL only covered duplicate-create.

Tests: symlinked root/dir/file rejection (create + update + delete), empty
description/body, concurrent create+update ordering, concurrent-create one-winner.
2026-06-14 14:00:19 +09:00
metaphorics 16bad4b47e fix(coding-agent): refuse symlinked managed-skill write targets
`writeManagedSkill` wrote `<managed-dir>/<name>/SKILL.md` via `Bun.write`,
which follows symlinks. A planted symlink at the `<name>` directory (or the
`SKILL.md` itself) could redirect the write outside the isolated managed root
and clobber a user-authored skill, breaking the isolation guarantee. lstat the
parent directory and the file and reject symlinks before writing; the existence
check now derives from the same lstat instead of a separate `Bun.file().exists()`.

Addresses review thread on PR #2542 (thread 11).
2026-06-14 12:36:31 +09:00
metaphorics 18ee97751a feat(coding-agent): opt-in experimental auto-learn (memory + isolated managed skills)
Add a default-off "auto-learn" loop. When `autolearn.enabled` is set, after the
agent stops a session controller nudges it to capture reusable lessons: durable
facts go to long-term memory and repeatable procedures become "managed skills" —
SKILL.md files written to an isolated ~/.omp/agent/managed-skills directory that is
discovered and surfaced like authored skills but never overwrites them.

Two tools back this:
- `manage_skill` — create/update/delete managed skills.
- `learn` — record a lesson, optionally minting/enhancing a managed skill in the
  same call (requires a hindsight/mnemopi memory backend).

The nudge is passive by default (a hidden reminder rides the next turn);
`autolearn.autoContinue` instead auto-runs one capture turn at stop, and
`autolearn.minToolCalls` (default 5) gates trivial turns. Plan/goal-mode turns and
subagents are never nudged, and the controller re-checks the live setting at fire
time so a mid-session opt-out takes effect.

Isolation & precedence: managed skills are a separate lowest-priority discovery
provider, so an authored skill of the same name wins across every provider and
custom directory regardless of third-party toggles; a disabled higher-priority
authored skill can never hide a managed one, and managed never masks an enabled
authored skill. Managed names and descriptions are sanitized on both write and
read (control/format chars, angle brackets, and Markdown fences) before they render
into the system prompt, and the SKILL.md byte cap is enforced on the final
serialized file.

Default off → zero footprint when disabled.
2026-06-14 10:45:23 +09:00