moflo 4.10.29 → 4.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/guidance/shipped/moflo-cross-install-memory-sharing.md +16 -6
- package/.claude/guidance/shipped/moflo-yaml-reference.md +2 -1
- package/.claude/skills/memory-team/SKILL.md +164 -0
- package/.claude/skills/memory-worktree/SKILL.md +127 -0
- package/README.md +2 -2
- package/bin/session-start-launcher.mjs +38 -5
- package/dist/src/cli/commands/doctor-checks-shared-db.js +13 -0
- package/dist/src/cli/config/moflo-config.js +20 -3
- package/dist/src/cli/init/executor.js +2 -0
- package/dist/src/cli/services/durable-sync.js +129 -15
- package/dist/src/cli/version.js +1 -1
- package/package.json +2 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Cross-Installation Memory Sharing
|
|
2
2
|
|
|
3
|
-
**Purpose:** Decide how to share moflo's durable learnings across git worktrees, machines, or a team —
|
|
3
|
+
**Purpose:** Decide how to share moflo's durable learnings across git worktrees, machines, or a team — WITHOUT corrupting search. Worktrees on one machine share automatically; read this before customizing that, running `flo memory sync`, or pointing two checkouts at one database.
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -26,7 +26,7 @@ Choose by who needs the learnings, not by what is easiest to wire.
|
|
|
26
26
|
|
|
27
27
|
| Topology | Mechanism | How |
|
|
28
28
|
|----------|-----------|-----|
|
|
29
|
-
| Same machine, many worktrees / Conductor workspaces |
|
|
29
|
+
| Same machine, many worktrees / Conductor workspaces | **Automatic** (default) | Learnings converge across worktrees at session-start with no config; override the store with `memory.durable_path`, or opt out with `memory.worktree_sharing: false` |
|
|
30
30
|
| One person, many machines | `flo memory sync` | `--to <file>` then `--from <file>` via a synced folder (Dropbox/iCloud) or a hand-copied file |
|
|
31
31
|
| A team sharing one repo | Git-tracked team artifact | `flo memory team-export` writes `.moflo/shared/learnings.jsonl`; teammates' session-start import-merges it after `git pull` |
|
|
32
32
|
| A fresh/empty workspace that must be ready FAST | Whole-DB snapshot (`memory.hydrate_from`) | `flo memory backup --to <snap>` once; a new workspace restores the entire DB so search works on session one — no cold reindex |
|
|
@@ -35,16 +35,25 @@ The first three move the SAME durable slice and dedupe on `UNIQUE(namespace, key
|
|
|
35
35
|
|
|
36
36
|
---
|
|
37
37
|
|
|
38
|
-
##
|
|
38
|
+
## Automatic Worktree Sharing (Default)
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
**Worktrees on one machine need no setup — sharing is automatic.** When moflo starts in a checkout whose repo has git worktrees in play, it derives a durable-only store at `<git-common-dir>/moflo/durable.db` (a path every worktree computes identically, since they share one `.git`) and converges `learnings` + `knowledge` across them at session-start. Conductor builds on git worktrees, so its workspaces are covered too.
|
|
41
|
+
|
|
42
|
+
| Guardrail | Behavior |
|
|
43
|
+
|-----------|----------|
|
|
44
|
+
| Activates only with worktrees | A plain single checkout writes nothing — byte-for-byte unchanged |
|
|
45
|
+
| Never a full DB | The derived store is a dedicated `durable.db`, so it can't trip the index-divergence hazard above |
|
|
46
|
+
| Opt out | `memory.worktree_sharing: false` |
|
|
47
|
+
| Override the location | `memory.durable_path` (also use this to converge separate *clones*, which don't share a `.git`) |
|
|
48
|
+
|
|
49
|
+
To override the store location, set a dedicated file — NOT a full `moflo.db`:
|
|
41
50
|
|
|
42
51
|
```yaml
|
|
43
52
|
memory:
|
|
44
|
-
durable_path: ~/.moflo-shared/team-learnings.db #
|
|
53
|
+
durable_path: ~/.moflo-shared/team-learnings.db # overrides the auto store; created on first flush
|
|
45
54
|
```
|
|
46
55
|
|
|
47
|
-
|
|
56
|
+
Pointing `durable_path` at a real `moflo.db` re-introduces the whole-DB-sharing hazard. `MOFLO_DURABLE_PATH` overrides per process; relative paths resolve against the project root. The `/memory-worktree` skill verifies, customizes, or opts out for you.
|
|
48
57
|
|
|
49
58
|
---
|
|
50
59
|
|
|
@@ -111,6 +120,7 @@ flo doctor -c shared-db
|
|
|
111
120
|
|
|
112
121
|
| Result | Meaning |
|
|
113
122
|
|--------|---------|
|
|
123
|
+
| **pass** — "Automatic worktree learning sharing active" | No `durable_path` set, but worktrees are present — the auto-derived durable-only store is on and safe |
|
|
114
124
|
| **pass** — "durable-only shared store configured" | `durable_path` points at a dedicated file — safe |
|
|
115
125
|
| **warn** — "points at a full moflo.db" | `durable_path` aliases or is named like a full DB — repoint it at a dedicated store |
|
|
116
126
|
| **warn** — "is a symlink" | The local `moflo.db` is symlinked into a shared location — replace it with a local DB and use `durable_path` |
|
|
@@ -60,7 +60,8 @@ memory:
|
|
|
60
60
|
backend: node-sqlite # node-sqlite (default) | rvf (pure-TS fallback) | json (last resort). Passed to createDatabase() as the preferred provider (#1144).
|
|
61
61
|
embedding_model: Xenova/all-MiniLM-L6-v2 # 384-dim neural embeddings
|
|
62
62
|
namespace: default # Default namespace for memory operations
|
|
63
|
-
#
|
|
63
|
+
# worktree_sharing: false # opt-OUT (#1231): automatic durable-learning sharing across git worktrees is ON by default (derived at <git-common-dir>/moflo/durable.db, active only when worktrees exist; a single checkout is untouched). Set false to disable.
|
|
64
|
+
# durable_path: ~/.moflo-shared/team-learnings.db # opt-in (#1232): OVERRIDE the auto worktree store — a custom durable-only path for learnings/knowledge, or to converge separate clones. Point at a DEDICATED store, never a full moflo.db. Env override: MOFLO_DURABLE_PATH.
|
|
64
65
|
# team_artifact: .moflo/shared/learnings.jsonl # opt-in (#1234): git-tracked JSONL the team commits; session-start import-merges it. Env override: MOFLO_TEAM_ARTIFACT. See moflo-cross-install-memory-sharing.md.
|
|
65
66
|
# hydrate_from: /abs/path/to/moflo-snapshot.db # opt-in (#1244): whole-DB snapshot to seed a fresh/empty workspace on session-start (skips the cold reindex). No-op once the local DB has content. Take one with "flo memory backup --to <path>". Env override: MOFLO_HYDRATE_FROM.
|
|
66
67
|
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: memory-team
|
|
3
|
+
description: |
|
|
4
|
+
Guided setup for sharing moflo's durable learnings through a git-tracked JSONL artifact — for a whole
|
|
5
|
+
TEAM on one repo, OR for one person across several MACHINES (a team of one). Use when the user says
|
|
6
|
+
"share learnings with my team", "commit our moflo memory", "sync memory across my laptop and desktop",
|
|
7
|
+
"set up memory.team_artifact", or "auto-export learnings on every PR". Installs a pre-commit hook so the
|
|
8
|
+
artifact rides along in every commit. For many worktrees on ONE machine, use /memory-worktree instead.
|
|
9
|
+
arguments: "[--solo]"
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# /memory-team — Share Learnings via a Git-Tracked Artifact
|
|
13
|
+
|
|
14
|
+
Wires up **`memory.team_artifact`**: a diffable JSONL file (`.moflo/shared/learnings.jsonl`) that lives
|
|
15
|
+
**in the repo**, reviewed like any other change. Teammates `git pull` it and their next session
|
|
16
|
+
auto-imports the merged learnings; each entry is stamped with its git author. This skill also installs a
|
|
17
|
+
**pre-commit hook** so the artifact is re-exported and staged on every commit — the learnings ride along
|
|
18
|
+
in each PR with zero effort.
|
|
19
|
+
|
|
20
|
+
> **One mechanism, two audiences.** A *team* and *one person across machines* are the same problem — push
|
|
21
|
+
> the durable slice through git. This skill covers both; the only difference is whether anyone else is on
|
|
22
|
+
> the other end. (Prefer a private, non-git file for your own machines? See "Advanced" at the bottom —
|
|
23
|
+
> `flo memory sync` moves a binary artifact that keeps embeddings verbatim.)
|
|
24
|
+
|
|
25
|
+
**Arguments:** `$ARGUMENTS` — pass `--solo` to skip team-oriented wording (still identical setup).
|
|
26
|
+
|
|
27
|
+
## When to use
|
|
28
|
+
|
|
29
|
+
- "share learnings / memory with my team"
|
|
30
|
+
- "commit our moflo knowledge to the repo"
|
|
31
|
+
- "sync memory between my laptop and desktop"
|
|
32
|
+
- "auto-export the learnings on every PR / commit"
|
|
33
|
+
- "set up `team_artifact`"
|
|
34
|
+
|
|
35
|
+
For **many worktrees on one machine**, that's a shared local store, not git — use `/memory-worktree`.
|
|
36
|
+
|
|
37
|
+
## Procedure
|
|
38
|
+
|
|
39
|
+
### Step 0 — Memory first (gate requirement)
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
mcp__moflo__memory_search { query: "team_artifact learnings jsonl git share import session-start", namespace: "guidance" }
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Step 1 — Confirm this is the git path
|
|
46
|
+
|
|
47
|
+
- Team on one repo, or one person across machines who both push to the same repo? → correct skill.
|
|
48
|
+
- Many worktrees on **one** machine, no cross-machine need? → redirect to `/memory-worktree`.
|
|
49
|
+
- A private synced file (Dropbox/USB), no git? → point at the Advanced section (`flo memory sync`).
|
|
50
|
+
|
|
51
|
+
### Step 2 — Set the config
|
|
52
|
+
|
|
53
|
+
Read the project-root `moflo.yaml` and add/merge under `memory:` — **preserve existing keys**:
|
|
54
|
+
|
|
55
|
+
```yaml
|
|
56
|
+
memory:
|
|
57
|
+
team_artifact: .moflo/shared/learnings.jsonl
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
`.moflo/shared/learnings.jsonl` is the default; only override if the user wants a different tracked path.
|
|
61
|
+
|
|
62
|
+
### Step 3 — First export (creates + tracks the artifact)
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
npx flo memory team-export 2>&1
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
This writes the JSONL, and **rewrites `.gitignore`** from a blanket `.moflo/` to `.moflo/*` +
|
|
69
|
+
`!/.moflo/shared/` so the shared artifact is tracked while the machine-local DB stays ignored. Surface
|
|
70
|
+
what it reports (entries added, `.gitignore` change). If there are no durable learnings yet, that's fine —
|
|
71
|
+
the artifact is created empty and fills in as learnings accrue.
|
|
72
|
+
|
|
73
|
+
### Step 4 — Install the pre-commit hook
|
|
74
|
+
|
|
75
|
+
The hook re-exports and stages the artifact on every commit, so it's never stale in a PR. Handle three
|
|
76
|
+
cases; **do not clobber** an existing hook.
|
|
77
|
+
|
|
78
|
+
Define the managed block (POSIX `sh` — git runs hooks via `sh` on Linux, macOS, **and** Windows):
|
|
79
|
+
|
|
80
|
+
```sh
|
|
81
|
+
# >>> moflo team-export (managed by /memory-team) >>>
|
|
82
|
+
# Refresh the shared learnings artifact so it rides along in this commit.
|
|
83
|
+
npx --no-install flo memory team-export >/dev/null 2>&1 || true
|
|
84
|
+
if [ -n "$(git status --porcelain -- .moflo/shared/learnings.jsonl 2>/dev/null)" ]; then
|
|
85
|
+
git add .moflo/shared/learnings.jsonl
|
|
86
|
+
fi
|
|
87
|
+
# <<< moflo team-export (managed by /memory-team) <<<
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Install it:
|
|
91
|
+
|
|
92
|
+
1. **Husky present** (`.husky/pre-commit` exists) → append the block to that file.
|
|
93
|
+
2. **Existing `.git/hooks/pre-commit`** → if it already contains the `moflo team-export` markers, leave it
|
|
94
|
+
(idempotent); otherwise append the block after the shebang.
|
|
95
|
+
3. **No hook** → create `.git/hooks/pre-commit` with `#!/bin/sh` as the first line, then the block.
|
|
96
|
+
|
|
97
|
+
On POSIX, make it executable:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
node -e "require('fs').chmodSync('.git/hooks/pre-commit', 0o755)"
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
(Use the Node `fs.chmodSync` primitive, not `chmod` — it's a harmless no-op on Windows. Never shell out
|
|
104
|
+
to `chmod` in a cross-platform step.)
|
|
105
|
+
|
|
106
|
+
- The `|| true` keeps a failed export from ever blocking a commit.
|
|
107
|
+
- The `git status --porcelain` guard means the artifact is only re-staged when it actually changed — no
|
|
108
|
+
empty-diff churn on unrelated commits.
|
|
109
|
+
|
|
110
|
+
### Step 5 — Commit and share
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
git add .moflo/shared/learnings.jsonl .gitignore
|
|
114
|
+
git commit -m "chore: share moflo learnings"
|
|
115
|
+
git push
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Teammates (or your other machine) run `git pull`; their **next session auto-imports** the merged file —
|
|
119
|
+
no manual import command. To pull learnings without waiting for a restart:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
npx flo memory team-import 2>&1
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Output
|
|
126
|
+
|
|
127
|
+
End with a single-block summary:
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
Team Memory Sharing — configured
|
|
131
|
+
─────────────────────────────────
|
|
132
|
+
Artifact: .moflo/shared/learnings.jsonl (git-tracked, JSONL, author-stamped)
|
|
133
|
+
Config key: memory.team_artifact
|
|
134
|
+
PR hook: .git/hooks/pre-commit → re-exports + stages on every commit
|
|
135
|
+
Import: automatic at session start (after git pull) | npx flo memory team-import
|
|
136
|
+
Scope: learnings + knowledge only (embeddings regenerated on import)
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Advanced — one person, a private file (no git)
|
|
140
|
+
|
|
141
|
+
If you're solo and would rather not commit learnings, carry a binary artifact instead. It keeps the
|
|
142
|
+
embeddings verbatim (no recompute on the far side) and merges idempotently:
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
npx flo memory sync --to ~/Dropbox/moflo-learnings.db # machine A
|
|
146
|
+
npx flo memory sync --from ~/Dropbox/moflo-learnings.db # machine B
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Same durable slice, no repo footprint, no review — the trade-off is it's not diffable and not shared.
|
|
150
|
+
|
|
151
|
+
## Rules
|
|
152
|
+
|
|
153
|
+
- **Don't** reimplement export/import or the `.gitignore` rewrite — `flo memory team-export/team-import`
|
|
154
|
+
own all of it (`team-artifact-sync.ts`). This skill sets config, runs them, and installs the hook.
|
|
155
|
+
- **Don't** overwrite an existing pre-commit hook or husky config — append the marked block only.
|
|
156
|
+
- **Don't** use `chmod` / `mkdir` / `rm` in shell steps — Windows lacks them on PATH; use Node `fs`.
|
|
157
|
+
- Embeddings are intentionally **omitted** from the JSONL (384 floats/row would wreck diffs) — they're
|
|
158
|
+
regenerated on import. Don't try to add them.
|
|
159
|
+
|
|
160
|
+
## See Also
|
|
161
|
+
|
|
162
|
+
- `/memory-worktree` — same-machine sharing across worktrees / Conductor (a shared local store, not git)
|
|
163
|
+
- `flo memory team-export --help` / `flo memory sync --help`
|
|
164
|
+
- `docs/blog/memory-sharing.html` — the design rationale (durable slice, why not share the whole DB)
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: memory-worktree
|
|
3
|
+
description: |
|
|
4
|
+
Verify, customize, or opt out of moflo's AUTOMATIC durable-learning sharing across git worktrees /
|
|
5
|
+
Conductor workspaces on one machine. As of the worktree-auto-sharing change this is on by default —
|
|
6
|
+
learnings converge across a repo's worktrees with no setup. Use when the user asks "is memory shared
|
|
7
|
+
across my worktrees?", "where are my worktree learnings stored?", "turn off worktree memory sharing",
|
|
8
|
+
"share learnings across my separate clones", or "point my worktrees at a custom store". For a team or
|
|
9
|
+
cross-machine (git-tracked) sharing, use /memory-team instead.
|
|
10
|
+
arguments: "[--off | --path <store>]"
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# /memory-worktree — Durable Sharing Across Worktrees (Automatic)
|
|
14
|
+
|
|
15
|
+
Working across git worktrees is a core moflo competency, so durable-learning sharing across the
|
|
16
|
+
worktrees of a repo is now **automatic and on by default**. When a checkout is part of a repo with
|
|
17
|
+
worktrees in play, moflo derives a shared durable store at **`<git-common-dir>/moflo/durable.db`** and
|
|
18
|
+
converges the `learnings` + `knowledge` namespaces across every worktree at session start — no config.
|
|
19
|
+
A plain single checkout writes nothing and behaves exactly as before.
|
|
20
|
+
|
|
21
|
+
This skill is for the three things you might still want: **verify** it's working, **customize** where it
|
|
22
|
+
stores (or extend it to non-worktree clones), or **opt out**.
|
|
23
|
+
|
|
24
|
+
> Only the durable slice travels. Structural + ephemeral data stays local per checkout and rebuilds
|
|
25
|
+
> itself — the same safety model the auto path is built on (a dedicated `durable.db`, never a full
|
|
26
|
+
> `moflo.db`). See [[memory-team]] for the git-tracked, cross-machine variant.
|
|
27
|
+
|
|
28
|
+
**Arguments:** `$ARGUMENTS` — `--off` to opt out, `--path <store>` to set a custom shared store.
|
|
29
|
+
|
|
30
|
+
## When to use
|
|
31
|
+
|
|
32
|
+
- "Is memory / are learnings shared across my worktrees?" → **verify** (Step 1).
|
|
33
|
+
- "Where are my worktree learnings stored?" → it's `<git-common-dir>/moflo/durable.db`; verify to confirm.
|
|
34
|
+
- "Turn off / disable worktree memory sharing" → **opt out** (Step 2).
|
|
35
|
+
- "Share learnings across my separate clones / a custom location" → **customize** (Step 3).
|
|
36
|
+
|
|
37
|
+
For a team, or your own laptop+desktop over git, that's `/memory-team`, not this.
|
|
38
|
+
|
|
39
|
+
## Procedure
|
|
40
|
+
|
|
41
|
+
### Step 0 — Memory first (gate requirement)
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
mcp__moflo__memory_search { query: "durable_path worktree sharing auto git common dir learnings", namespace: "guidance" }
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Step 1 — Verify (default action)
|
|
48
|
+
|
|
49
|
+
Run the safety/status check and surface it verbatim:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
npx flo doctor -c shared-db 2>&1
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
- **"Automatic worktree learning sharing active (<path>)"** → it's working; the path is the shared store.
|
|
56
|
+
- **"No shared full moflo.db detected…"** → auto sharing is NOT active here. Most likely this checkout
|
|
57
|
+
has no sibling worktrees yet (auto only turns on once worktrees exist). Confirm with the user; if they
|
|
58
|
+
expected sharing across *separate clones* (not worktrees), go to Step 3 — auto can't converge those.
|
|
59
|
+
- **A `warn`** → a full-DB misconfig is present; follow the check's `fix` line.
|
|
60
|
+
|
|
61
|
+
To see that learnings actually converged, from a second worktree:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
npx flo memory list --namespace learnings 2>&1 | head
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Step 2 — Opt out (`--off`)
|
|
68
|
+
|
|
69
|
+
If the user wants it off, set the toggle in the project-root `moflo.yaml` (preserve other `memory:` keys):
|
|
70
|
+
|
|
71
|
+
```yaml
|
|
72
|
+
memory:
|
|
73
|
+
worktree_sharing: false
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Explain: this stops the auto flush/seed at session start. Anything already converged into a worktree's
|
|
77
|
+
local DB stays; nothing new propagates. Takes effect next session.
|
|
78
|
+
|
|
79
|
+
### Step 3 — Customize the store (`--path`, or non-worktree clones)
|
|
80
|
+
|
|
81
|
+
Setting an explicit `memory.durable_path` **overrides** the auto derivation — use it to:
|
|
82
|
+
- put the shared store somewhere other than `.git/moflo/` (e.g. a synced/backed-up location), or
|
|
83
|
+
- converge checkouts that are **separate clones**, not git worktrees (auto only covers worktrees, since
|
|
84
|
+
only worktrees share a git common dir).
|
|
85
|
+
|
|
86
|
+
```yaml
|
|
87
|
+
memory:
|
|
88
|
+
durable_path: ~/.moflo-shared/<repo-name>-learnings.db
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
The path must live outside any single checkout and must **not** be named `moflo.db`. Create the parent
|
|
92
|
+
dir with a Node primitive (cross-platform — never `mkdir -p`):
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
node -e "const p=require('path'),fs=require('fs');fs.mkdirSync(p.dirname(process.argv[1]),{recursive:true})" "<chosen-store-path>"
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Then re-run `npx flo doctor -c shared-db` to confirm it reports the durable-only store as safe.
|
|
99
|
+
|
|
100
|
+
## Output
|
|
101
|
+
|
|
102
|
+
End with a single-block summary of what state you left it in, e.g.:
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
Worktree Memory Sharing
|
|
106
|
+
────────────────────────
|
|
107
|
+
Mode: automatic (default) | custom durable_path | disabled
|
|
108
|
+
Store: <git-common-dir>/moflo/durable.db (or the custom/none path)
|
|
109
|
+
Config: memory.worktree_sharing / memory.durable_path
|
|
110
|
+
Verify: npx flo doctor -c shared-db
|
|
111
|
+
Scope: learnings + knowledge only (structural stays local)
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Rules
|
|
115
|
+
|
|
116
|
+
- **Don't** re-implement the sync or path derivation — it's `resolveDurablePath` / `syncDurableAtSessionStart`
|
|
117
|
+
in `src/cli/services/durable-sync.ts`; this skill only reads config, sets the two keys, and verifies.
|
|
118
|
+
- **Never** set `durable_path` to a file named `moflo.db` or the local `.moflo/moflo.db` — that's the
|
|
119
|
+
HNSW-index-divergence hazard `flo doctor -c shared-db` guards against.
|
|
120
|
+
- **Don't** use `mkdir -p` / `rm` / `cp` in shell steps — Windows lacks them on PATH. Use Node `fs`.
|
|
121
|
+
- **Cross-machine or team? Wrong skill.** Redirect to `/memory-team`.
|
|
122
|
+
|
|
123
|
+
## See Also
|
|
124
|
+
|
|
125
|
+
- `/memory-team` — git-tracked JSONL sharing for teams **and** one person across machines
|
|
126
|
+
- `flo doctor -c shared-db` — reports auto-sharing status and catches full-DB misconfig
|
|
127
|
+
- `docs/blog/memory-sharing.html` — the design rationale (durable vs structural vs ephemeral)
|
package/README.md
CHANGED
|
@@ -67,7 +67,7 @@ MoFlo makes deliberate choices so you don't have to:
|
|
|
67
67
|
|---------|-------------|
|
|
68
68
|
| **Semantic Memory** | 384-dim domain-aware embeddings. Store knowledge, search it instantly. |
|
|
69
69
|
| **Reflection** | Distills durable lessons from your sessions into searchable memory — automatically (auto-meditate), or on demand with `/meditate`. |
|
|
70
|
-
| **Cross-Install Sharing** |
|
|
70
|
+
| **Cross-Install Sharing** | Durable `learnings` follow you across git worktrees **automatically** (no setup) — and across your own machines or a whole team via `flo memory sync` or a git-tracked artifact. Structural namespaces stay local. [Full documentation →](.claude/guidance/shipped/moflo-cross-install-memory-sharing.md) |
|
|
71
71
|
| **Code Navigation** | Indexes your codebase structure so Claude can answer "where does X live?" without Glob/Grep. |
|
|
72
72
|
| **Guidance Indexing** | Chunks your project docs (`.claude/guidance/`, `docs/`) and makes them searchable. |
|
|
73
73
|
| **Gates** | Enforces memory-first and task-creation patterns via Claude Code hooks. Prevents Claude from skipping steps. |
|
|
@@ -271,7 +271,7 @@ Pick the mechanism by topology:
|
|
|
271
271
|
|
|
272
272
|
| You want to share across… | Use | How |
|
|
273
273
|
|---------------------------|-----|-----|
|
|
274
|
-
| Git worktrees / Conductor workspaces (same machine) |
|
|
274
|
+
| Git worktrees / Conductor workspaces (same machine) | **Automatic** — nothing to set | Learnings converge across worktrees at session-start (stored at `<git-common-dir>/moflo/durable.db`). Override with `memory.durable_path`; opt out with `memory.worktree_sharing: false` |
|
|
275
275
|
| Your own laptop + desktop + CI | `flo memory sync --to/--from <file>` | Export to a synced folder (Dropbox/iCloud) or a copied file, import on the other machine |
|
|
276
276
|
| A whole team on one repo | `flo memory team-export` → commit `.moflo/shared/learnings.jsonl` | Teammates' session-start import-merges it after `git pull` (first-write-wins; author provenance retained) |
|
|
277
277
|
| A fresh workspace that must be ready fast | `flo memory backup/restore` or `memory.hydrate_from` | Seed a new workspace from a **whole-DB snapshot** so it's searchable on session one — no cold reindex. Safe because each workspace owns its own copy (a one-time restore, not live sharing) |
|
|
@@ -2175,11 +2175,38 @@ try {
|
|
|
2175
2175
|
// override is set or moflo.yaml has an UNcommented `durable_path:` line (the
|
|
2176
2176
|
// generated config ships a commented example, which this regex ignores).
|
|
2177
2177
|
const durableYamlPath = resolve(projectRoot, 'moflo.yaml');
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2178
|
+
// Read moflo.yaml ONCE, then run every pre-gate regex against the one string —
|
|
2179
|
+
// every consumer with a moflo.yaml pays a single read here, not one per key.
|
|
2180
|
+
let durableYaml = '';
|
|
2181
|
+
try {
|
|
2182
|
+
if (existsSync(durableYamlPath)) durableYaml = readFileSync(durableYamlPath, 'utf-8');
|
|
2183
|
+
} catch { /* unreadable yaml — treat as not-configured */ }
|
|
2184
|
+
let durableEnabled = Boolean(process.env.MOFLO_DURABLE_PATH) || /^[ \t]*durable_path[ \t]*:/m.test(durableYaml);
|
|
2185
|
+
// Auto-enable across git worktrees — moflo's core multi-worktree competency.
|
|
2186
|
+
// When durable_path isn't explicitly configured, still run the sync IF this
|
|
2187
|
+
// repo has worktrees in play (this checkout is a linked worktree, or the
|
|
2188
|
+
// shared .git has a non-empty worktrees/ registry), unless the user opted out
|
|
2189
|
+
// with `worktree_sharing: false`. A plain single checkout short-circuits on a
|
|
2190
|
+
// cheap fs stat with no module import, so solo users pay ~nothing. The
|
|
2191
|
+
// authoritative derivation lives in durable-sync.ts#resolveDurablePath.
|
|
2192
|
+
if (!durableEnabled) {
|
|
2193
|
+
const optedOut = /^[ \t]*(worktree_sharing|worktreeSharing)[ \t]*:[ \t]*false\b/m.test(durableYaml);
|
|
2194
|
+
if (!optedOut) {
|
|
2195
|
+
try {
|
|
2196
|
+
const dotgit = join(projectRoot, '.git');
|
|
2197
|
+
const st = statSync(dotgit);
|
|
2198
|
+
if (st.isFile()) {
|
|
2199
|
+
// Linked worktree — `.git` file's `gitdir:` points into `.git/worktrees/…`.
|
|
2200
|
+
// A submodule's points into `.git/modules/…` (no worktrees segment) and
|
|
2201
|
+
// must NOT auto-share with its superproject, so gate on the segment.
|
|
2202
|
+
if (/[\\/]worktrees[\\/]/.test(readFileSync(dotgit, 'utf-8'))) durableEnabled = true;
|
|
2203
|
+
} else if (st.isDirectory()) {
|
|
2204
|
+
try {
|
|
2205
|
+
if (readdirSync(join(dotgit, 'worktrees')).length > 0) durableEnabled = true;
|
|
2206
|
+
} catch { /* no worktrees registry (ENOENT) — stay off */ }
|
|
2207
|
+
}
|
|
2208
|
+
} catch { /* no/unreadable .git — not a worktree, stay off */ }
|
|
2209
|
+
}
|
|
2183
2210
|
}
|
|
2184
2211
|
const durablePaths = durableEnabled
|
|
2185
2212
|
? [
|
|
@@ -2191,6 +2218,12 @@ try {
|
|
|
2191
2218
|
if (durablePath) {
|
|
2192
2219
|
const { syncDurableAtSessionStart } = await import(pathToFileURL(durablePath).href);
|
|
2193
2220
|
const result = await syncDurableAtSessionStart({ projectRoot });
|
|
2221
|
+
if (result?.autoWorktree && (result.seededToLocal > 0 || result.flushedToShared > 0)) {
|
|
2222
|
+
emitMutation(
|
|
2223
|
+
'auto-shared learnings across git worktrees',
|
|
2224
|
+
'converging durable learnings for this repo — set memory.worktree_sharing: false to opt out',
|
|
2225
|
+
);
|
|
2226
|
+
}
|
|
2194
2227
|
if (result?.seededToLocal > 0) {
|
|
2195
2228
|
emitMutation(
|
|
2196
2229
|
'seeded shared learnings',
|
|
@@ -22,6 +22,7 @@ import * as path from 'path';
|
|
|
22
22
|
import { memoryDbPath } from '../services/moflo-paths.js';
|
|
23
23
|
import { findProjectRoot } from '../services/project-root.js';
|
|
24
24
|
import { loadMofloConfig } from '../config/moflo-config.js';
|
|
25
|
+
import { resolveDurablePath } from '../services/durable-sync.js';
|
|
25
26
|
import { errorDetail } from '../shared/utils/error-detail.js';
|
|
26
27
|
const NAME = 'Shared Full DB';
|
|
27
28
|
/**
|
|
@@ -99,6 +100,18 @@ export async function checkSharedFullDb(deps) {
|
|
|
99
100
|
message: `Durable-only shared store configured (${durableRaw}) — safe; structural namespaces stay local.`,
|
|
100
101
|
};
|
|
101
102
|
}
|
|
103
|
+
// 3. No explicit durable_path — surface automatic worktree sharing when it's
|
|
104
|
+
// active, so the default-on behavior is visible (and reassuringly safe:
|
|
105
|
+
// the derived store is a dedicated durable.db, never a full moflo.db).
|
|
106
|
+
const auto = resolveDurablePath(root, config);
|
|
107
|
+
if (auto.autoWorktree && auto.path) {
|
|
108
|
+
return {
|
|
109
|
+
name: NAME,
|
|
110
|
+
status: 'pass',
|
|
111
|
+
message: `Automatic worktree learning sharing active (${auto.path}) — durable learnings converge across this ` +
|
|
112
|
+
`repo's git worktrees; structural namespaces stay local. Set memory.worktree_sharing: false to disable.`,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
102
115
|
return {
|
|
103
116
|
name: NAME,
|
|
104
117
|
status: 'pass',
|
|
@@ -228,6 +228,13 @@ function mergeConfig(raw, root) {
|
|
|
228
228
|
const v = raw.memory?.durable_path ?? raw.memory?.durablePath;
|
|
229
229
|
return typeof v === 'string' && v.trim().length > 0 ? v.trim() : undefined;
|
|
230
230
|
})(),
|
|
231
|
+
// #1231 follow-up — opt-out toggle for automatic worktree learning
|
|
232
|
+
// sharing. Only an explicit `false` disables it; absent/true leaves the
|
|
233
|
+
// default auto-behavior on. Detection + derivation live in durable-sync.ts.
|
|
234
|
+
worktree_sharing: (() => {
|
|
235
|
+
const v = raw.memory?.worktree_sharing ?? raw.memory?.worktreeSharing;
|
|
236
|
+
return typeof v === 'boolean' ? v : undefined;
|
|
237
|
+
})(),
|
|
231
238
|
team_artifact: (() => {
|
|
232
239
|
const v = raw.memory?.team_artifact ?? raw.memory?.teamArtifact;
|
|
233
240
|
return typeof v === 'string' && v.trim().length > 0 ? v.trim() : undefined;
|
|
@@ -340,11 +347,21 @@ function mergeConfig(raw, root) {
|
|
|
340
347
|
* Tries moflo.yaml first, then moflo.config.json.
|
|
341
348
|
* Returns defaults merged with file contents.
|
|
342
349
|
*/
|
|
350
|
+
/**
|
|
351
|
+
* A fresh defaults-only config for `root`. Deep-clones DEFAULT_CONFIG so a caller
|
|
352
|
+
* mutating the returned config's nested objects (e.g. `cfg.memory.durable_path =
|
|
353
|
+
* …`) can't poison the module-global DEFAULT_CONFIG and leak into every later
|
|
354
|
+
* load — a shallow spread shares the nested `memory`/`hooks`/… references, a
|
|
355
|
+
* latent cross-contamination bug.
|
|
356
|
+
*/
|
|
357
|
+
function freshDefaultConfig(root) {
|
|
358
|
+
return { ...structuredClone(DEFAULT_CONFIG), project: { name: path.basename(root) } };
|
|
359
|
+
}
|
|
343
360
|
export function loadMofloConfig(projectRoot) {
|
|
344
361
|
const root = projectRoot || process.cwd();
|
|
345
362
|
const configFile = findConfigFile(root);
|
|
346
363
|
if (!configFile) {
|
|
347
|
-
return
|
|
364
|
+
return freshDefaultConfig(root);
|
|
348
365
|
}
|
|
349
366
|
try {
|
|
350
367
|
const content = fs.readFileSync(configFile.path, 'utf-8');
|
|
@@ -360,12 +377,12 @@ export function loadMofloConfig(projectRoot) {
|
|
|
360
377
|
throw new Error('js-yaml is required to parse moflo.yaml. Install it: npm install js-yaml');
|
|
361
378
|
}
|
|
362
379
|
if (!raw || typeof raw !== 'object') {
|
|
363
|
-
return
|
|
380
|
+
return freshDefaultConfig(root);
|
|
364
381
|
}
|
|
365
382
|
return mergeConfig(raw, root);
|
|
366
383
|
}
|
|
367
384
|
catch {
|
|
368
|
-
return
|
|
385
|
+
return freshDefaultConfig(root);
|
|
369
386
|
}
|
|
370
387
|
}
|
|
371
388
|
/**
|
|
@@ -48,6 +48,8 @@ export const SKILLS_MAP = {
|
|
|
48
48
|
'memory-patterns',
|
|
49
49
|
'memory-optimization',
|
|
50
50
|
'vector-search',
|
|
51
|
+
'memory-worktree', // guided memory.durable_path setup (same-machine worktrees)
|
|
52
|
+
'memory-team', // guided memory.team_artifact setup + PR pre-commit hook
|
|
51
53
|
],
|
|
52
54
|
spells: [
|
|
53
55
|
'spell-builder',
|
|
@@ -33,6 +33,8 @@
|
|
|
33
33
|
*
|
|
34
34
|
* @module cli/services/durable-sync
|
|
35
35
|
*/
|
|
36
|
+
import * as path from 'path';
|
|
37
|
+
import * as fs from 'fs';
|
|
36
38
|
import { findProjectRoot } from './project-root.js';
|
|
37
39
|
import { stableAbsolute, pickConfiguredPath } from './configured-path.js';
|
|
38
40
|
import { memoryDbPath } from './moflo-paths.js';
|
|
@@ -40,24 +42,127 @@ import { loadMofloConfig } from '../config/moflo-config.js';
|
|
|
40
42
|
import { cherryPickLearningsFromLegacy, DURABLE_NAMESPACES, isDurableNamespace, } from './cherry-pick-learnings.js';
|
|
41
43
|
export { isDurableNamespace };
|
|
42
44
|
/**
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
45
|
+
* Read `<projectRoot>/.git` ONCE and classify the checkout for worktree sharing,
|
|
46
|
+
* using filesystem reads only (no `git` subprocess, so it's PATH-independent and
|
|
47
|
+
* cross-platform, Rule #1). Returns the shared `.git` common dir plus whether
|
|
48
|
+
* THIS checkout is a linked worktree — or `null` when it's not a git repo root,
|
|
49
|
+
* `.git` is unreadable, or it's a **submodule**.
|
|
47
50
|
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
+
* - Primary checkout: `<root>/.git` is a directory → that IS the common dir.
|
|
52
|
+
* - Linked worktree: `<root>/.git` is a FILE (`gitdir: <main>/.git/worktrees/<id>`)
|
|
53
|
+
* whose `commondir` file points back to the shared `.git`.
|
|
54
|
+
* - Submodule: `<root>/.git` is also a FILE, but `gitdir: <super>/.git/modules/<name>`
|
|
55
|
+
* with NO `commondir`. It is NOT a worktree and must NEVER share a durable
|
|
56
|
+
* store with its superproject — excluded via the `worktrees/` segment +
|
|
57
|
+
* `commondir` checks (real worktrees have both; submodules have neither).
|
|
58
|
+
*
|
|
59
|
+
* The primary tree and all its worktrees resolve to the SAME common dir, which
|
|
60
|
+
* is what lets an auto-derived shared store converge with zero config.
|
|
61
|
+
*/
|
|
62
|
+
function readGitLayout(projectRoot) {
|
|
63
|
+
const dotgit = path.join(projectRoot, '.git');
|
|
64
|
+
let st;
|
|
65
|
+
try {
|
|
66
|
+
st = fs.statSync(dotgit);
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
if (st.isDirectory())
|
|
72
|
+
return { commonDir: dotgit, linkedWorktree: false };
|
|
73
|
+
if (!st.isFile())
|
|
74
|
+
return null;
|
|
75
|
+
try {
|
|
76
|
+
const m = fs.readFileSync(dotgit, 'utf-8').match(/gitdir:\s*(.+)/);
|
|
77
|
+
if (!m)
|
|
78
|
+
return null;
|
|
79
|
+
let gitdir = m[1].trim();
|
|
80
|
+
if (!path.isAbsolute(gitdir))
|
|
81
|
+
gitdir = path.resolve(projectRoot, gitdir);
|
|
82
|
+
// Linked worktree only — exclude submodules (`.../modules/...`, no commondir).
|
|
83
|
+
if (!/[\\/]worktrees[\\/]/.test(gitdir))
|
|
84
|
+
return null;
|
|
85
|
+
let cd = fs.readFileSync(path.join(gitdir, 'commondir'), 'utf-8').trim();
|
|
86
|
+
if (!path.isAbsolute(cd))
|
|
87
|
+
cd = path.resolve(gitdir, cd);
|
|
88
|
+
return { commonDir: path.resolve(cd), linkedWorktree: true };
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/** The shared git common dir for `projectRoot`, or `null` — see {@link readGitLayout}. */
|
|
95
|
+
export function resolveGitCommonDir(projectRoot) {
|
|
96
|
+
return readGitLayout(projectRoot)?.commonDir ?? null;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Decide whether to AUTO-enable durable sharing for `projectRoot`, returning the
|
|
100
|
+
* shared `.git` common dir to derive the store under — or `null` to stay off.
|
|
101
|
+
*
|
|
102
|
+
* Activates ONLY when git worktrees are actually in play, so a plain single
|
|
103
|
+
* checkout (and any submodule) writes nothing and behaves byte-identically to
|
|
104
|
+
* before. "In play" = this checkout is itself a linked worktree, OR the shared
|
|
105
|
+
* `.git` has a non-empty `worktrees/` registry (a sibling worktree exists).
|
|
106
|
+
*/
|
|
107
|
+
export function detectWorktreeCommonDir(projectRoot) {
|
|
108
|
+
const layout = readGitLayout(projectRoot);
|
|
109
|
+
if (!layout)
|
|
110
|
+
return null;
|
|
111
|
+
if (layout.linkedWorktree)
|
|
112
|
+
return layout.commonDir;
|
|
113
|
+
// Primary checkout — activate only if it has registered linked worktrees.
|
|
114
|
+
try {
|
|
115
|
+
if (fs.readdirSync(path.join(layout.commonDir, 'worktrees')).length > 0)
|
|
116
|
+
return layout.commonDir;
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
/* no worktrees registry (ENOENT) or unreadable — treat as no worktrees */
|
|
120
|
+
}
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Resolve the durable-store path to an absolute path, or `null` when there's
|
|
125
|
+
* nothing to sync.
|
|
126
|
+
*
|
|
127
|
+
* Precedence:
|
|
128
|
+
* 1. Explicit config — `MOFLO_DURABLE_PATH` env > `memory.durable_path`
|
|
129
|
+
* (moflo.yaml). Relative values resolve against the project root.
|
|
130
|
+
* 2. Auto worktree sharing — when NOTHING is explicitly configured, moflo's
|
|
131
|
+
* multi-worktree competency kicks in: if this checkout is part of a repo
|
|
132
|
+
* with git worktrees in play, derive a shared store at
|
|
133
|
+
* `<git-common-dir>/moflo/durable.db`. Every worktree of the repo resolves
|
|
134
|
+
* to the same path, so their learnings converge with zero config. Opt out
|
|
135
|
+
* with `memory.worktree_sharing: false`. A single checkout (no worktrees)
|
|
136
|
+
* derives nothing and stays byte-identical to before.
|
|
137
|
+
*
|
|
138
|
+
* A store that aliases this project's own local DB is rejected (syncing a DB
|
|
139
|
+
* with itself is a no-op). Path-pick + symlink-stable identity live in
|
|
140
|
+
* {@link pickConfiguredPath}/{@link stableAbsolute}.
|
|
51
141
|
*/
|
|
52
142
|
export function resolveDurablePath(projectRoot = findProjectRoot(), config) {
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
143
|
+
const cfg = config ?? loadMofloConfig(projectRoot);
|
|
144
|
+
const local = () => stableAbsolute(memoryDbPath(projectRoot));
|
|
145
|
+
const abs = pickConfiguredPath(process.env.MOFLO_DURABLE_PATH, cfg.memory.durable_path, projectRoot);
|
|
146
|
+
if (abs) {
|
|
147
|
+
// Self-reference guard — never let the shared store alias the local DB.
|
|
148
|
+
if (stableAbsolute(abs) === local()) {
|
|
149
|
+
return { path: null, skipped: 'same-as-local' };
|
|
150
|
+
}
|
|
151
|
+
return { path: abs };
|
|
59
152
|
}
|
|
60
|
-
|
|
153
|
+
// No explicit config → auto-share across git worktrees unless opted out.
|
|
154
|
+
if (cfg.memory.worktree_sharing !== false) {
|
|
155
|
+
const commonDir = detectWorktreeCommonDir(projectRoot);
|
|
156
|
+
if (commonDir) {
|
|
157
|
+
const derived = path.join(commonDir, 'moflo', 'durable.db');
|
|
158
|
+
// Paranoia guard — a derived path should never alias the local DB, but a
|
|
159
|
+
// pathological `.git` layout shouldn't turn into a self-sync.
|
|
160
|
+
if (stableAbsolute(derived) !== local()) {
|
|
161
|
+
return { path: derived, autoWorktree: true };
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return { path: null, skipped: 'not-configured' };
|
|
61
166
|
}
|
|
62
167
|
/**
|
|
63
168
|
* Seed durable rows from the shared store into this project's local DB.
|
|
@@ -77,6 +182,14 @@ export async function seedDurableFromShared(projectRoot, durablePath) {
|
|
|
77
182
|
* Local is the source, the shared store the target (created on first flush).
|
|
78
183
|
*/
|
|
79
184
|
export async function flushDurableToShared(projectRoot, durablePath) {
|
|
185
|
+
// Ensure the parent dir exists — auto-derived worktree stores live under
|
|
186
|
+
// `<git-common-dir>/moflo/`, which won't exist on the very first flush.
|
|
187
|
+
try {
|
|
188
|
+
fs.mkdirSync(path.dirname(durablePath), { recursive: true });
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
/* a real open failure surfaces from cherry-pick below */
|
|
192
|
+
}
|
|
80
193
|
return cherryPickLearningsFromLegacy({
|
|
81
194
|
projectRoot,
|
|
82
195
|
legacyPaths: [memoryDbPath(projectRoot)],
|
|
@@ -96,7 +209,7 @@ export async function flushDurableToShared(projectRoot, durablePath) {
|
|
|
96
209
|
*/
|
|
97
210
|
export async function syncDurableAtSessionStart(opts = {}) {
|
|
98
211
|
const projectRoot = opts.projectRoot ?? findProjectRoot();
|
|
99
|
-
const { path: durablePath, skipped } = resolveDurablePath(projectRoot, opts.config);
|
|
212
|
+
const { path: durablePath, skipped, autoWorktree } = resolveDurablePath(projectRoot, opts.config);
|
|
100
213
|
if (!durablePath) {
|
|
101
214
|
return { durablePath: null, skipped, flushedToShared: 0, seededToLocal: 0 };
|
|
102
215
|
}
|
|
@@ -106,6 +219,7 @@ export async function syncDurableAtSessionStart(opts = {}) {
|
|
|
106
219
|
const seed = await seedDurableFromShared(projectRoot, durablePath);
|
|
107
220
|
return {
|
|
108
221
|
durablePath,
|
|
222
|
+
autoWorktree: autoWorktree ?? false,
|
|
109
223
|
flushedToShared: flush.copied,
|
|
110
224
|
seededToLocal: seed.copied,
|
|
111
225
|
};
|
package/dist/src/cli/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "moflo",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.11.0",
|
|
4
4
|
"description": "MoFlo — AI agent orchestration for Claude Code. A standalone, opinionated toolkit with semantic memory, learned routing, gates, spells, and the /flo issue-execution skill.",
|
|
5
5
|
"main": "dist/src/cli/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -94,7 +94,7 @@
|
|
|
94
94
|
"@typescript-eslint/eslint-plugin": "^7.18.0",
|
|
95
95
|
"@typescript-eslint/parser": "^7.18.0",
|
|
96
96
|
"eslint": "^8.0.0",
|
|
97
|
-
"moflo": "^4.10.29
|
|
97
|
+
"moflo": "^4.10.29",
|
|
98
98
|
"tsx": "^4.21.0",
|
|
99
99
|
"typescript": "^5.9.3",
|
|
100
100
|
"vitest": "^4.0.0"
|