moflo 4.9.35 → 4.9.36
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.
|
@@ -435,7 +435,7 @@ function generateClaudeMd(root, _force) {
|
|
|
435
435
|
// scriptFiles array in bin/session-start-launcher.mjs — first-init drops any
|
|
436
436
|
// script missing here, and the launcher's manifest cleanup later treats it as
|
|
437
437
|
// orphan residue and deletes it (#777, feedback_scriptfiles_sync.md).
|
|
438
|
-
const SCRIPT_MAP = [
|
|
438
|
+
export const SCRIPT_MAP = [
|
|
439
439
|
'hooks.mjs',
|
|
440
440
|
'session-start-launcher.mjs',
|
|
441
441
|
'index-guidance.mjs',
|
|
@@ -496,17 +496,25 @@ function isStale(srcPath, destPath) {
|
|
|
496
496
|
// ============================================================================
|
|
497
497
|
// Step 6: .gitignore
|
|
498
498
|
// ============================================================================
|
|
499
|
-
function updateGitignore(root) {
|
|
499
|
+
export function updateGitignore(root) {
|
|
500
500
|
const gitignorePath = path.join(root, '.gitignore');
|
|
501
501
|
const entries = [
|
|
502
502
|
'.claude-epic/',
|
|
503
503
|
'.moflo/',
|
|
504
504
|
'.swarm/',
|
|
505
|
-
'.moflo/',
|
|
506
505
|
'.claude/settings.local.json',
|
|
507
506
|
'.claude/scheduled_tasks.lock',
|
|
508
507
|
'**/workflow-state.json',
|
|
508
|
+
// Leading `/` anchors to gitignore root — bare `.claude/guidance/` once
|
|
509
|
+
// swallowed shipped/internal subdirs and broke `npm pack`
|
|
510
|
+
// (guidance-gitignore-shipped-trap).
|
|
511
|
+
'/.claude/guidance/moflo-*.md',
|
|
512
|
+
...SCRIPT_MAP.map(name => `/.claude/scripts/${name}`),
|
|
509
513
|
];
|
|
514
|
+
// Treat `/.foo` and `.foo` as the same rule when checking for prior presence
|
|
515
|
+
// — both forms anchor at gitignore root, so a consumer who wrote either
|
|
516
|
+
// shouldn't get a duplicate appended.
|
|
517
|
+
const normalize = (s) => s.replace(/^\//, '');
|
|
510
518
|
if (!fs.existsSync(gitignorePath)) {
|
|
511
519
|
const defaultEntries = ['node_modules/', 'dist/', '.env', '.env.*', ''];
|
|
512
520
|
const content = '# Dependencies\n' + defaultEntries.join('\n') + '\n# MoFlo state\n' + entries.join('\n') + '\n';
|
|
@@ -514,8 +522,8 @@ function updateGitignore(root) {
|
|
|
514
522
|
return { name: '.gitignore', status: 'created', detail: 'Created with node_modules, .env, and MoFlo entries' };
|
|
515
523
|
}
|
|
516
524
|
const existing = fs.readFileSync(gitignorePath, 'utf-8');
|
|
517
|
-
const existingLines = new Set(existing.split(/\r?\n/).map(l => l.trim()).filter(l => l && !l.startsWith('#')));
|
|
518
|
-
const toAdd = entries.filter(e => !existingLines.has(e));
|
|
525
|
+
const existingLines = new Set(existing.split(/\r?\n/).map(l => normalize(l.trim())).filter(l => l && !l.startsWith('#')));
|
|
526
|
+
const toAdd = entries.filter(e => !existingLines.has(normalize(e)));
|
|
519
527
|
if (toAdd.length === 0) {
|
|
520
528
|
return { name: '.gitignore', status: 'skipped', detail: 'Entries already present' };
|
|
521
529
|
}
|
|
@@ -12,11 +12,11 @@
|
|
|
12
12
|
* @module moflo/cli/memory/auto-memory-bridge
|
|
13
13
|
*/
|
|
14
14
|
import { createHash } from 'node:crypto';
|
|
15
|
-
import { homedir } from 'node:os';
|
|
16
15
|
import { EventEmitter } from 'node:events';
|
|
17
16
|
import * as fs from 'node:fs/promises';
|
|
18
17
|
import { existsSync, readFileSync, readdirSync } from 'node:fs';
|
|
19
18
|
import * as path from 'node:path';
|
|
19
|
+
import { claudeProjectDirFor } from '../shared/utils/claude-projects-path.js';
|
|
20
20
|
import { createDefaultEntry, } from './types.js';
|
|
21
21
|
import { LearningBridge } from './learning-bridge.js';
|
|
22
22
|
import { MemoryGraph } from './memory-graph.js';
|
|
@@ -539,20 +539,17 @@ export class AutoMemoryBridge extends EventEmitter {
|
|
|
539
539
|
// ===== Utility Functions =====
|
|
540
540
|
/**
|
|
541
541
|
* Resolve the auto memory directory for a given working directory.
|
|
542
|
-
*
|
|
542
|
+
*
|
|
543
|
+
* The git root is preferred over the raw cwd so a session in
|
|
544
|
+
* `<repo>/packages/foo` resolves to the repo's auto-memory store, matching
|
|
545
|
+
* Claude Code's own behaviour. The encoded suffix is produced by the shared
|
|
546
|
+
* `claudeProjectDirFor` helper so this bridge cannot drift away from the
|
|
547
|
+
* Claude Code directory naming convention (issue #1048).
|
|
543
548
|
*/
|
|
544
549
|
export function resolveAutoMemoryDir(workingDir) {
|
|
545
550
|
const gitRoot = findGitRoot(workingDir);
|
|
546
551
|
const basePath = gitRoot || workingDir;
|
|
547
|
-
|
|
548
|
-
// The leading dash IS preserved (e.g. /workspaces/foo -> -workspaces-foo)
|
|
549
|
-
// On Windows, strip drive letter prefix (C:) for cleaner keys
|
|
550
|
-
let normalized = basePath.split(path.sep).join('/');
|
|
551
|
-
if (process.platform === 'win32') {
|
|
552
|
-
normalized = normalized.replace(/^[A-Za-z]:/, '');
|
|
553
|
-
}
|
|
554
|
-
const projectKey = normalized.replace(/\//g, '-');
|
|
555
|
-
return path.join(homedir(), '.claude', 'projects', projectKey, 'memory');
|
|
552
|
+
return path.join(claudeProjectDirFor(basePath), 'memory');
|
|
556
553
|
}
|
|
557
554
|
/**
|
|
558
555
|
* Find the git root directory by walking up from workingDir.
|
|
@@ -22,9 +22,10 @@
|
|
|
22
22
|
*/
|
|
23
23
|
import { createReadStream } from 'node:fs';
|
|
24
24
|
import { stat, readdir } from 'node:fs/promises';
|
|
25
|
-
import { homedir } from 'node:os';
|
|
26
25
|
import { join } from 'node:path';
|
|
27
26
|
import { createInterface } from 'node:readline';
|
|
27
|
+
import { claudeProjectDirFor, encodeCwdForClaudeProjects, } from '../shared/utils/claude-projects-path.js';
|
|
28
|
+
export { claudeProjectDirFor, encodeCwdForClaudeProjects };
|
|
28
29
|
/**
|
|
29
30
|
* Map a transcript model name to a stable display key. Recognises bare family
|
|
30
31
|
* names ("opus", "sonnet", "haiku"), dated/dotted variants
|
|
@@ -43,21 +44,6 @@ export function canonicalModelKey(model) {
|
|
|
43
44
|
return 'haiku';
|
|
44
45
|
return 'unknown';
|
|
45
46
|
}
|
|
46
|
-
// ============================================================================
|
|
47
|
-
// Path resolution
|
|
48
|
-
// ============================================================================
|
|
49
|
-
/**
|
|
50
|
-
* Encode a CWD the same way Claude Code does for `~/.claude/projects/<dir>`.
|
|
51
|
-
* Replaces `\`, `/`, and `:` with `-` so `C:\Users\eric\Projects\moflo` →
|
|
52
|
-
* `C--Users-eric-Projects-moflo`.
|
|
53
|
-
*/
|
|
54
|
-
export function encodeCwdForClaudeProjects(cwd) {
|
|
55
|
-
return cwd.replace(/[\\/:]/g, '-');
|
|
56
|
-
}
|
|
57
|
-
/** Absolute path to `~/.claude/projects/<encoded-cwd>` for the given CWD. */
|
|
58
|
-
export function claudeProjectDirFor(cwd) {
|
|
59
|
-
return join(homedir(), '.claude', 'projects', encodeCwdForClaudeProjects(cwd));
|
|
60
|
-
}
|
|
61
47
|
const CACHE_TTL_MS = 30_000;
|
|
62
48
|
let cache = null;
|
|
63
49
|
/** Test-only — drop the in-memory cache so the next call re-aggregates. */
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Encode a working directory the same way Claude Code does for its
|
|
3
|
+
* `~/.claude/projects/<dir>/` transcript & memory store.
|
|
4
|
+
*
|
|
5
|
+
* Claude Code replaces *every* non-alphanumeric character in the absolute
|
|
6
|
+
* path with `-`. Earlier moflo versions used a narrower class (`/[\\/:]/g`,
|
|
7
|
+
* or split-and-rejoin variants) which agreed with Claude Code only for
|
|
8
|
+
* paths whose every other character was alphanumeric — issue #1048.
|
|
9
|
+
*
|
|
10
|
+
* Centralised here so the stats aggregator and the auto-memory bridge
|
|
11
|
+
* cannot drift apart.
|
|
12
|
+
*/
|
|
13
|
+
import { homedir } from 'node:os';
|
|
14
|
+
import { join } from 'node:path';
|
|
15
|
+
/**
|
|
16
|
+
* Encode a CWD to the form Claude Code uses as a `~/.claude/projects/`
|
|
17
|
+
* subdirectory name. Replaces every non-alphanumeric character with `-`.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* encodeCwdForClaudeProjects('C:\\Users\\me\\some_project')
|
|
21
|
+
* → 'C--Users-me-some-project'
|
|
22
|
+
* encodeCwdForClaudeProjects('/Users/me/dev/some_project')
|
|
23
|
+
* → '-Users-me-dev-some-project'
|
|
24
|
+
*/
|
|
25
|
+
export function encodeCwdForClaudeProjects(cwd) {
|
|
26
|
+
return cwd.replace(/[^A-Za-z0-9]/g, '-');
|
|
27
|
+
}
|
|
28
|
+
/** Absolute path to `~/.claude/projects/<encoded-cwd>` for the given CWD. */
|
|
29
|
+
export function claudeProjectDirFor(cwd) {
|
|
30
|
+
return join(homedir(), '.claude', 'projects', encodeCwdForClaudeProjects(cwd));
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=claude-projects-path.js.map
|
package/dist/src/cli/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "moflo",
|
|
3
|
-
"version": "4.9.
|
|
3
|
+
"version": "4.9.36",
|
|
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",
|
|
@@ -97,7 +97,7 @@
|
|
|
97
97
|
"@typescript-eslint/eslint-plugin": "^7.18.0",
|
|
98
98
|
"@typescript-eslint/parser": "^7.18.0",
|
|
99
99
|
"eslint": "^8.0.0",
|
|
100
|
-
"moflo": "^4.9.
|
|
100
|
+
"moflo": "^4.9.35",
|
|
101
101
|
"tsx": "^4.21.0",
|
|
102
102
|
"typescript": "^5.9.3",
|
|
103
103
|
"vitest": "^4.0.0"
|