Skip to content

Add WorkspaceModule, remove FilesModule#19

Merged
Anarchid merged 7 commits into
anima-research:mainfrom
Tengro:feature/workspace-module
Mar 23, 2026
Merged

Add WorkspaceModule, remove FilesModule#19
Anarchid merged 7 commits into
anima-research:mainfrom
Tengro:feature/workspace-module

Conversation

@Tengro
Copy link
Copy Markdown
Collaborator

@Tengro Tengro commented Mar 23, 2026

Summary

  • Add WorkspaceModule — mountable filesystem abstraction backed by Chronicle's tree state strategy
  • Remove FilesModule — superseded by WorkspaceModule with a broader feature set
  • Add chokidar dependency for filesystem watching
  • Add missing safe-slice.ts — imported by framework.ts but file was absent

WorkspaceModule features

  • Mount-based access: multiple filesystem mounts with path prefixes (project/src/main.ts)
  • Three watch modes: always (chokidar), on-agent-action (sync after tool calls), never (fully virtual)
  • Manual materialization: agent controls when Chronicle state is written to disk
  • Lazy sync: files are read from filesystem into Chronicle on first access
  • 10 tools: read, write, edit, delete, ls, glob, grep, status, materialize, sync
  • Conflict detection: filesystem wins on conflict, agent's version preserved in Chronicle history

New files

  • src/modules/workspace/index.ts — main module class with tool handlers
  • src/modules/workspace/types.ts — config, state, and tool input types
  • src/modules/workspace/watcher.ts — chokidar wrapper with debounce and write suppression
  • src/modules/workspace/sync.ts — bidirectional sync logic (fs↔Chronicle)
  • src/safe-slice.ts — surrogate-pair-safe string slice (was imported but missing)

Dependencies

Test plan

  • npx tsc --noEmit passes
  • Clean npx tsc build succeeds
  • Merge conflict with upstream/main resolved (FilesModule deletion vs upstream input validation)
  • Integration test: mount directory, read/write/edit files through WorkspaceModule
  • Test materialize/sync cycle
  • Test watcher debounce and suppression

🤖 Generated with Claude Code

Tengro and others added 7 commits March 20, 2026 14:43
Replace FilesModule with WorkspaceModule — a mountable filesystem
abstraction backed by Chronicle's new tree state strategy. Features:
- Mount-based filesystem access with path prefixes
- Three watch modes: always (chokidar), on-agent-action, never
- Manual materialization (Chronicle → filesystem)
- Lazy sync (filesystem → Chronicle on demand)
- 10 tools: read, write, edit, delete, ls, glob, grep, status,
  materialize, sync
- Conflict detection (filesystem wins, agent version preserved in history)

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

# Conflicts:
#	src/modules/files/index.ts
The safeSlice function is imported by framework.ts (from upstream) but
the file was not included. Creates a surrogate-pair-safe string slice
to avoid producing invalid UTF-16 when truncating tool results.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Prevents materialization to disk when the current Chronicle branch
differs from the branch that was last materialized. This ensures
subagent branches don't overwrite the main branch's filesystem state.

- Track lastMaterializedBranchId per mount
- Guard handleMaterialize: reject if branch mismatch (default: on)
- Persist branch info in module state for restart recovery
- Show branch status in workspace:status output (canMaterialize flag)
- Config: set materializeOnlyActiveBranch: false to disable

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ction, type safety

- Add path traversal guard in parsePath() (CWE-22 prevention)
- Initialize materializedHashes in MountState, record hashes on materialize
- Make watcher.stop() async, await chokidar close()
- Remove as unknown as ProcessEvent double-casts (add index sigs to event types)
- Replace ! non-null assertions with early-return validation
- Add {a,b,c} alternation support to globToRegex()

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Chronicle's JsTreeChange now always uses old_entry/new_entry instead of
the ambiguous entry field. Update the diff consumer accordingly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Tests:
- Update tool names from test:echo to test--echo (matching : → -- separator
  change in module-registry). All 19 tests now pass.

Security:
- Add safePath() guard in syncFromFs and materializeToFs — resolve()+
  startsWith() check prevents writes outside mount from corrupted/malicious
  tree entries (closes the back door that parsePath guards the front of).

Performance:
- Remove onAgentActionSync — agent write/edit/delete already update the
  tree correctly, so full-mount directory walk after each tool call was
  O(n) wasted I/O. Users can call workspace:sync explicitly.

API improvements:
- Conflict reports now include agentBlobHash so the agent's overwritten
  version is recoverable via store.getBlob().
- Document supported ignore pattern subset in MountConfig (not gitignore).

Cleanup:
- Remove dead createHash import from index.ts
- Deduplicate DEFAULT_MAX_FILE_SIZE (export from sync.ts)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@Anarchid Anarchid merged commit 407358b into anima-research:main Mar 23, 2026
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.

2 participants