@lumenflow/memory 1.0.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/LICENSE +190 -0
- package/README.md +181 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/mem-checkpoint-core.d.ts +91 -0
- package/dist/mem-checkpoint-core.d.ts.map +1 -0
- package/dist/mem-checkpoint-core.js +175 -0
- package/dist/mem-checkpoint-core.js.map +1 -0
- package/dist/mem-cleanup-core.d.ts +202 -0
- package/dist/mem-cleanup-core.d.ts.map +1 -0
- package/dist/mem-cleanup-core.js +364 -0
- package/dist/mem-cleanup-core.js.map +1 -0
- package/dist/mem-create-core.d.ts +93 -0
- package/dist/mem-create-core.d.ts.map +1 -0
- package/dist/mem-create-core.js +369 -0
- package/dist/mem-create-core.js.map +1 -0
- package/dist/mem-id.d.ts +91 -0
- package/dist/mem-id.d.ts.map +1 -0
- package/dist/mem-id.js +136 -0
- package/dist/mem-id.js.map +1 -0
- package/dist/mem-init-core.d.ts +91 -0
- package/dist/mem-init-core.d.ts.map +1 -0
- package/dist/mem-init-core.js +138 -0
- package/dist/mem-init-core.js.map +1 -0
- package/dist/mem-ready-core.d.ts +56 -0
- package/dist/mem-ready-core.d.ts.map +1 -0
- package/dist/mem-ready-core.js +232 -0
- package/dist/mem-ready-core.js.map +1 -0
- package/dist/mem-signal-core.d.ts +132 -0
- package/dist/mem-signal-core.d.ts.map +1 -0
- package/dist/mem-signal-core.js +249 -0
- package/dist/mem-signal-core.js.map +1 -0
- package/dist/mem-start-core.d.ts +76 -0
- package/dist/mem-start-core.d.ts.map +1 -0
- package/dist/mem-start-core.js +133 -0
- package/dist/mem-start-core.js.map +1 -0
- package/dist/mem-summarize-core.d.ts +105 -0
- package/dist/mem-summarize-core.d.ts.map +1 -0
- package/dist/mem-summarize-core.js +263 -0
- package/dist/mem-summarize-core.js.map +1 -0
- package/dist/mem-triage-core.d.ts +127 -0
- package/dist/mem-triage-core.d.ts.map +1 -0
- package/dist/mem-triage-core.js +332 -0
- package/dist/mem-triage-core.js.map +1 -0
- package/dist/memory-schema.d.ts +150 -0
- package/dist/memory-schema.d.ts.map +1 -0
- package/dist/memory-schema.js +149 -0
- package/dist/memory-schema.js.map +1 -0
- package/dist/memory-store.d.ts +108 -0
- package/dist/memory-store.d.ts.map +1 -0
- package/dist/memory-store.js +234 -0
- package/dist/memory-store.js.map +1 -0
- package/package.json +76 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory Init Core (WU-1464)
|
|
3
|
+
*
|
|
4
|
+
* Core logic for initializing memory layer in a repository.
|
|
5
|
+
* Creates .beacon/memory/ directory with empty memory.jsonl and config.yaml.
|
|
6
|
+
*
|
|
7
|
+
* @see {@link tools/__tests__/mem-init.test.mjs} - Tests
|
|
8
|
+
* @see {@link tools/lib/memory-store.mjs} - Memory store operations
|
|
9
|
+
* @see {@link tools/lib/memory-schema.mjs} - Memory schema definitions
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Memory layer file/directory paths
|
|
13
|
+
*/
|
|
14
|
+
export declare const MEMORY_PATHS: {
|
|
15
|
+
/** Memory directory relative to project root */
|
|
16
|
+
MEMORY_DIR: string;
|
|
17
|
+
/** Memory JSONL file name */
|
|
18
|
+
MEMORY_FILE: string;
|
|
19
|
+
/** Config YAML file name */
|
|
20
|
+
CONFIG_FILE: string;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Default memory layer configuration
|
|
24
|
+
*
|
|
25
|
+
* Retention values are in seconds:
|
|
26
|
+
* - ephemeral: 0 (immediate discard)
|
|
27
|
+
* - session: 3600 (1 hour)
|
|
28
|
+
* - wu: 604800 (7 days)
|
|
29
|
+
* - project: -1 (never expire)
|
|
30
|
+
*/
|
|
31
|
+
export declare const DEFAULT_CONFIG: {
|
|
32
|
+
/** Config schema version */
|
|
33
|
+
version: number;
|
|
34
|
+
/** Retention policy for each lifecycle */
|
|
35
|
+
retention: {
|
|
36
|
+
/** Ephemeral nodes are discarded immediately after use */
|
|
37
|
+
ephemeral: number;
|
|
38
|
+
/** Session nodes expire after 1 hour */
|
|
39
|
+
session: number;
|
|
40
|
+
/** WU nodes expire after 7 days */
|
|
41
|
+
wu: number;
|
|
42
|
+
/** Project nodes never expire (-1 = infinite) */
|
|
43
|
+
project: number;
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Memory initialization paths
|
|
48
|
+
*/
|
|
49
|
+
interface InitMemoryPaths {
|
|
50
|
+
memoryDir: string;
|
|
51
|
+
memoryJsonl: string;
|
|
52
|
+
configYaml: string;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Memory initialization created flags
|
|
56
|
+
*/
|
|
57
|
+
interface InitMemoryCreated {
|
|
58
|
+
directory: boolean;
|
|
59
|
+
memoryJsonl: boolean;
|
|
60
|
+
configYaml: boolean;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Memory initialization result
|
|
64
|
+
*/
|
|
65
|
+
export interface InitMemoryResult {
|
|
66
|
+
success: boolean;
|
|
67
|
+
alreadyInitialized: boolean;
|
|
68
|
+
paths: InitMemoryPaths;
|
|
69
|
+
created: InitMemoryCreated;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Initialize memory layer in a repository.
|
|
73
|
+
*
|
|
74
|
+
* Creates:
|
|
75
|
+
* - .beacon/memory/ directory
|
|
76
|
+
* - memory.jsonl (empty if not exists)
|
|
77
|
+
* - config.yaml (default settings if not exists)
|
|
78
|
+
*
|
|
79
|
+
* Idempotent: Running multiple times does not corrupt existing data.
|
|
80
|
+
*
|
|
81
|
+
* @param baseDir - Base directory of the repository
|
|
82
|
+
* @returns Result object with success, paths, and created flags
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* const result = await initMemory(process.cwd());
|
|
86
|
+
* if (result.success) {
|
|
87
|
+
* console.log('Memory initialized at:', result.paths.memoryDir);
|
|
88
|
+
* }
|
|
89
|
+
*/
|
|
90
|
+
export declare function initMemory(baseDir: string): Promise<InitMemoryResult>;
|
|
91
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mem-init-core.d.ts","sourceRoot":"","sources":["../src/mem-init-core.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH;;GAEG;AACH,eAAO,MAAM,YAAY;IACvB,gDAAgD;;IAGhD,6BAA6B;;IAG7B,4BAA4B;;CAE7B,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,cAAc;IACzB,4BAA4B;;IAG5B,0CAA0C;;QAExC,0DAA0D;;QAE1D,wCAAwC;;QAExC,mCAAmC;;QAEnC,iDAAiD;;;CAGpD,CAAC;AA2BF;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,UAAU,CAAC,OAAO,KAAA;;;;;;;;;;;;;GAqDvC"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory Init Core (WU-1464)
|
|
3
|
+
*
|
|
4
|
+
* Core logic for initializing memory layer in a repository.
|
|
5
|
+
* Creates .beacon/memory/ directory with empty memory.jsonl and config.yaml.
|
|
6
|
+
*
|
|
7
|
+
* @see {@link tools/__tests__/mem-init.test.mjs} - Tests
|
|
8
|
+
* @see {@link tools/lib/memory-store.mjs} - Memory store operations
|
|
9
|
+
* @see {@link tools/lib/memory-schema.mjs} - Memory schema definitions
|
|
10
|
+
*/
|
|
11
|
+
import fs from 'node:fs/promises';
|
|
12
|
+
import path from 'node:path';
|
|
13
|
+
import yaml from 'yaml';
|
|
14
|
+
/**
|
|
15
|
+
* Memory layer file/directory paths
|
|
16
|
+
*/
|
|
17
|
+
export const MEMORY_PATHS = {
|
|
18
|
+
/** Memory directory relative to project root */
|
|
19
|
+
MEMORY_DIR: '.beacon/memory',
|
|
20
|
+
/** Memory JSONL file name */
|
|
21
|
+
MEMORY_FILE: 'memory.jsonl',
|
|
22
|
+
/** Config YAML file name */
|
|
23
|
+
CONFIG_FILE: 'config.yaml',
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Default memory layer configuration
|
|
27
|
+
*
|
|
28
|
+
* Retention values are in seconds:
|
|
29
|
+
* - ephemeral: 0 (immediate discard)
|
|
30
|
+
* - session: 3600 (1 hour)
|
|
31
|
+
* - wu: 604800 (7 days)
|
|
32
|
+
* - project: -1 (never expire)
|
|
33
|
+
*/
|
|
34
|
+
export const DEFAULT_CONFIG = {
|
|
35
|
+
/** Config schema version */
|
|
36
|
+
version: 1,
|
|
37
|
+
/** Retention policy for each lifecycle */
|
|
38
|
+
retention: {
|
|
39
|
+
/** Ephemeral nodes are discarded immediately after use */
|
|
40
|
+
ephemeral: 0,
|
|
41
|
+
/** Session nodes expire after 1 hour */
|
|
42
|
+
session: 3600,
|
|
43
|
+
/** WU nodes expire after 7 days */
|
|
44
|
+
wu: 604800,
|
|
45
|
+
/** Project nodes never expire (-1 = infinite) */
|
|
46
|
+
project: -1,
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Check if a file exists
|
|
51
|
+
*
|
|
52
|
+
* @param filePath - Path to check
|
|
53
|
+
* @returns True if file exists
|
|
54
|
+
*/
|
|
55
|
+
async function fileExists(filePath) {
|
|
56
|
+
try {
|
|
57
|
+
await fs.access(filePath);
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Generate config.yaml content from DEFAULT_CONFIG
|
|
66
|
+
*
|
|
67
|
+
* @returns YAML content string
|
|
68
|
+
*/
|
|
69
|
+
function generateConfigYaml() {
|
|
70
|
+
const header = '# Memory layer configuration\n# Generated by pnpm mem:init (WU-1464)\n';
|
|
71
|
+
return header + yaml.stringify(DEFAULT_CONFIG);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Initialize memory layer in a repository.
|
|
75
|
+
*
|
|
76
|
+
* Creates:
|
|
77
|
+
* - .beacon/memory/ directory
|
|
78
|
+
* - memory.jsonl (empty if not exists)
|
|
79
|
+
* - config.yaml (default settings if not exists)
|
|
80
|
+
*
|
|
81
|
+
* Idempotent: Running multiple times does not corrupt existing data.
|
|
82
|
+
*
|
|
83
|
+
* @param baseDir - Base directory of the repository
|
|
84
|
+
* @returns Result object with success, paths, and created flags
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* const result = await initMemory(process.cwd());
|
|
88
|
+
* if (result.success) {
|
|
89
|
+
* console.log('Memory initialized at:', result.paths.memoryDir);
|
|
90
|
+
* }
|
|
91
|
+
*/
|
|
92
|
+
export async function initMemory(baseDir) {
|
|
93
|
+
const memoryDir = path.join(baseDir, MEMORY_PATHS.MEMORY_DIR);
|
|
94
|
+
const memoryJsonlPath = path.join(memoryDir, MEMORY_PATHS.MEMORY_FILE);
|
|
95
|
+
const configYamlPath = path.join(memoryDir, MEMORY_PATHS.CONFIG_FILE);
|
|
96
|
+
const result = {
|
|
97
|
+
success: false,
|
|
98
|
+
alreadyInitialized: false,
|
|
99
|
+
paths: {
|
|
100
|
+
memoryDir,
|
|
101
|
+
memoryJsonl: memoryJsonlPath,
|
|
102
|
+
configYaml: configYamlPath,
|
|
103
|
+
},
|
|
104
|
+
created: {
|
|
105
|
+
directory: false,
|
|
106
|
+
memoryJsonl: false,
|
|
107
|
+
configYaml: false,
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
// Check if already initialized
|
|
111
|
+
const dirExists = await fileExists(memoryDir);
|
|
112
|
+
const memoryExists = await fileExists(memoryJsonlPath);
|
|
113
|
+
const configExists = await fileExists(configYamlPath);
|
|
114
|
+
if (dirExists && memoryExists && configExists) {
|
|
115
|
+
result.alreadyInitialized = true;
|
|
116
|
+
}
|
|
117
|
+
// Create directory if needed
|
|
118
|
+
if (!dirExists) {
|
|
119
|
+
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool creates .beacon/memory/ directory
|
|
120
|
+
await fs.mkdir(memoryDir, { recursive: true });
|
|
121
|
+
result.created.directory = true;
|
|
122
|
+
}
|
|
123
|
+
// Create empty memory.jsonl if needed
|
|
124
|
+
if (!memoryExists) {
|
|
125
|
+
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool creates memory.jsonl
|
|
126
|
+
await fs.writeFile(memoryJsonlPath, '', { encoding: 'utf-8' });
|
|
127
|
+
result.created.memoryJsonl = true;
|
|
128
|
+
}
|
|
129
|
+
// Create config.yaml with defaults if needed
|
|
130
|
+
if (!configExists) {
|
|
131
|
+
const configContent = generateConfigYaml();
|
|
132
|
+
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool creates config.yaml
|
|
133
|
+
await fs.writeFile(configYamlPath, configContent, { encoding: 'utf-8' });
|
|
134
|
+
result.created.configYaml = true;
|
|
135
|
+
}
|
|
136
|
+
result.success = true;
|
|
137
|
+
return result;
|
|
138
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mem-init-core.js","sourceRoot":"","sources":["../src/mem-init-core.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory Ready Core (WU-1468)
|
|
3
|
+
*
|
|
4
|
+
* Deterministic ready-work query for "what next?" oracle.
|
|
5
|
+
* Returns open nodes with no blockers, ordered by priority then createdAt.
|
|
6
|
+
*
|
|
7
|
+
* Ordering algorithm:
|
|
8
|
+
* 1. Priority ASC (P0 first, then P1, P2, P3; nodes without priority last)
|
|
9
|
+
* 2. CreatedAt ASC (oldest first for same priority)
|
|
10
|
+
* 3. ID ASC (stable sort for identical priority and timestamp)
|
|
11
|
+
*
|
|
12
|
+
* A node is "ready" if:
|
|
13
|
+
* - Linked to the specified WU
|
|
14
|
+
* - Not blocked by another node (no `blocks` relationship pointing to it)
|
|
15
|
+
* - No `metadata.blocked_by` array set
|
|
16
|
+
* - Lifecycle is not `ephemeral`
|
|
17
|
+
* - Status is not `closed` (metadata.status !== 'closed')
|
|
18
|
+
*
|
|
19
|
+
* @see {@link tools/mem-ready.mjs} - CLI implementation
|
|
20
|
+
* @see {@link tools/__tests__/mem-ready.test.mjs} - Tests
|
|
21
|
+
*/
|
|
22
|
+
import { type MemoryNode } from './memory-schema.js';
|
|
23
|
+
/**
|
|
24
|
+
* Query options for ready nodes
|
|
25
|
+
*/
|
|
26
|
+
export interface QueryOptions {
|
|
27
|
+
/** WU ID to query (required) */
|
|
28
|
+
wuId: string;
|
|
29
|
+
/** Filter by node type (optional) */
|
|
30
|
+
type?: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Query ready nodes for a WU.
|
|
34
|
+
*
|
|
35
|
+
* Returns unblocked, open nodes linked to the WU in deterministic order:
|
|
36
|
+
* 1. Priority (P0 first, then P1, P2, P3; nodes without priority last)
|
|
37
|
+
* 2. CreatedAt (oldest first for same priority)
|
|
38
|
+
* 3. ID (alphabetical for stable sort)
|
|
39
|
+
*
|
|
40
|
+
* @param baseDir - Base directory containing .beacon/memory
|
|
41
|
+
* @param options - Query options
|
|
42
|
+
* @returns Deterministically ordered ready nodes
|
|
43
|
+
* @throws If WU ID format is invalid or file contains malformed JSON
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* const ready = await queryReadyNodes('/path/to/project', { wuId: 'WU-1234' });
|
|
47
|
+
* console.log(`${ready.length} nodes ready for processing`);
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* // Filter by type
|
|
51
|
+
* const discoveries = await queryReadyNodes('/path/to/project', {
|
|
52
|
+
* wuId: 'WU-1234',
|
|
53
|
+
* type: 'discovery',
|
|
54
|
+
* });
|
|
55
|
+
*/
|
|
56
|
+
export declare function queryReadyNodes(baseDir: string, options: QueryOptions): Promise<MemoryNode[]>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mem-ready-core.d.ts","sourceRoot":"","sources":["../src/mem-ready-core.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAkLH;;;;GAIG;AAEH;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,eAAe,CAAC,OAAO,KAAA,EAAE,OAAO,KAAA,gBAwCrD"}
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory Ready Core (WU-1468)
|
|
3
|
+
*
|
|
4
|
+
* Deterministic ready-work query for "what next?" oracle.
|
|
5
|
+
* Returns open nodes with no blockers, ordered by priority then createdAt.
|
|
6
|
+
*
|
|
7
|
+
* Ordering algorithm:
|
|
8
|
+
* 1. Priority ASC (P0 first, then P1, P2, P3; nodes without priority last)
|
|
9
|
+
* 2. CreatedAt ASC (oldest first for same priority)
|
|
10
|
+
* 3. ID ASC (stable sort for identical priority and timestamp)
|
|
11
|
+
*
|
|
12
|
+
* A node is "ready" if:
|
|
13
|
+
* - Linked to the specified WU
|
|
14
|
+
* - Not blocked by another node (no `blocks` relationship pointing to it)
|
|
15
|
+
* - No `metadata.blocked_by` array set
|
|
16
|
+
* - Lifecycle is not `ephemeral`
|
|
17
|
+
* - Status is not `closed` (metadata.status !== 'closed')
|
|
18
|
+
*
|
|
19
|
+
* @see {@link tools/mem-ready.mjs} - CLI implementation
|
|
20
|
+
* @see {@link tools/__tests__/mem-ready.test.mjs} - Tests
|
|
21
|
+
*/
|
|
22
|
+
import fs from 'node:fs/promises';
|
|
23
|
+
import path from 'node:path';
|
|
24
|
+
import { loadMemory } from './memory-store.js';
|
|
25
|
+
import { MEMORY_PATTERNS } from './memory-schema.js';
|
|
26
|
+
/**
|
|
27
|
+
* Relationships file name
|
|
28
|
+
*/
|
|
29
|
+
const RELATIONSHIPS_FILE_NAME = 'relationships.jsonl';
|
|
30
|
+
/**
|
|
31
|
+
* Priority ranking for deterministic ordering.
|
|
32
|
+
* Lower rank = higher priority.
|
|
33
|
+
* P0 is highest priority, nodes without priority are lowest.
|
|
34
|
+
*/
|
|
35
|
+
const PRIORITY_RANK = {
|
|
36
|
+
P0: 0,
|
|
37
|
+
P1: 1,
|
|
38
|
+
P2: 2,
|
|
39
|
+
P3: 3,
|
|
40
|
+
};
|
|
41
|
+
/** Default rank for nodes without priority (lowest priority) */
|
|
42
|
+
const DEFAULT_PRIORITY_RANK = 999;
|
|
43
|
+
/**
|
|
44
|
+
* Gets the priority rank for a node.
|
|
45
|
+
* Lower rank = higher priority.
|
|
46
|
+
*
|
|
47
|
+
* @param node - Memory node
|
|
48
|
+
* @returns Priority rank
|
|
49
|
+
*/
|
|
50
|
+
function getPriorityRank(node) {
|
|
51
|
+
const priority = node.metadata?.priority;
|
|
52
|
+
if (!priority) {
|
|
53
|
+
return DEFAULT_PRIORITY_RANK;
|
|
54
|
+
}
|
|
55
|
+
return PRIORITY_RANK[priority] ?? DEFAULT_PRIORITY_RANK;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Comparator for deterministic ordering: priority first, then createdAt, then ID.
|
|
59
|
+
*
|
|
60
|
+
* @param a - First node
|
|
61
|
+
* @param b - Second node
|
|
62
|
+
* @returns Comparison result (-1, 0, 1)
|
|
63
|
+
*/
|
|
64
|
+
function compareNodes(a, b) {
|
|
65
|
+
// Primary: sort by priority (lower rank first)
|
|
66
|
+
const priorityDiff = getPriorityRank(a) - getPriorityRank(b);
|
|
67
|
+
if (priorityDiff !== 0) {
|
|
68
|
+
return priorityDiff;
|
|
69
|
+
}
|
|
70
|
+
// Secondary: sort by created_at (oldest first)
|
|
71
|
+
const aTime = new Date(a.created_at).getTime();
|
|
72
|
+
const bTime = new Date(b.created_at).getTime();
|
|
73
|
+
if (aTime !== bTime) {
|
|
74
|
+
return aTime - bTime;
|
|
75
|
+
}
|
|
76
|
+
// Tertiary: stable sort by ID for identical priority and timestamp
|
|
77
|
+
return a.id.localeCompare(b.id);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Load relationships from relationships.jsonl
|
|
81
|
+
*
|
|
82
|
+
* @param memoryDir - Memory directory path
|
|
83
|
+
* @returns Array of relationship objects
|
|
84
|
+
*/
|
|
85
|
+
async function loadRelationships(memoryDir) {
|
|
86
|
+
const filePath = path.join(memoryDir, RELATIONSHIPS_FILE_NAME);
|
|
87
|
+
try {
|
|
88
|
+
// eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool reads known file path
|
|
89
|
+
const content = await fs.readFile(filePath, { encoding: 'utf-8' });
|
|
90
|
+
const lines = content.split('\n');
|
|
91
|
+
const relationships = [];
|
|
92
|
+
for (const line of lines) {
|
|
93
|
+
const trimmed = line.trim();
|
|
94
|
+
if (!trimmed)
|
|
95
|
+
continue;
|
|
96
|
+
try {
|
|
97
|
+
relationships.push(JSON.parse(trimmed));
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
// Skip malformed lines in relationships file
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return relationships;
|
|
105
|
+
}
|
|
106
|
+
catch (err) {
|
|
107
|
+
const error = err;
|
|
108
|
+
if (error.code === 'ENOENT') {
|
|
109
|
+
// File doesn't exist - no relationships
|
|
110
|
+
return [];
|
|
111
|
+
}
|
|
112
|
+
throw error;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Build a set of node IDs that are blocked by relationships
|
|
117
|
+
*
|
|
118
|
+
* @param relationships - Relationship objects
|
|
119
|
+
* @returns Set of blocked node IDs
|
|
120
|
+
*/
|
|
121
|
+
function buildBlockedSet(relationships) {
|
|
122
|
+
const blocked = new Set();
|
|
123
|
+
for (const rel of relationships) {
|
|
124
|
+
if (rel.type === 'blocks') {
|
|
125
|
+
// The `to_id` is the blocked node
|
|
126
|
+
blocked.add(rel.to_id);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return blocked;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Check if a node is blocked
|
|
133
|
+
*
|
|
134
|
+
* @param node - Memory node
|
|
135
|
+
* @param blockedByRelationships - Set of IDs blocked by relationships
|
|
136
|
+
* @returns True if node is blocked
|
|
137
|
+
*/
|
|
138
|
+
function isBlocked(node, blockedByRelationships) {
|
|
139
|
+
// Check if blocked by relationship
|
|
140
|
+
if (blockedByRelationships.has(node.id)) {
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
143
|
+
// Check if blocked by metadata
|
|
144
|
+
const blockedBy = node.metadata?.blocked_by;
|
|
145
|
+
if (Array.isArray(blockedBy) && blockedBy.length > 0) {
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Check if a node is closed (not open for processing)
|
|
152
|
+
*
|
|
153
|
+
* @param node - Memory node
|
|
154
|
+
* @returns True if node is closed
|
|
155
|
+
*/
|
|
156
|
+
function isClosed(node) {
|
|
157
|
+
// Ephemeral nodes are considered closed (discarded after use)
|
|
158
|
+
if (node.lifecycle === 'ephemeral') {
|
|
159
|
+
return true;
|
|
160
|
+
}
|
|
161
|
+
// Check explicit closed status in metadata
|
|
162
|
+
if (node.metadata?.status === 'closed') {
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Validate WU ID format
|
|
169
|
+
*
|
|
170
|
+
* @param wuId - WU ID to validate
|
|
171
|
+
* @throws If WU ID format is invalid
|
|
172
|
+
*/
|
|
173
|
+
function validateWuId(wuId) {
|
|
174
|
+
if (!MEMORY_PATTERNS.WU_ID.test(wuId)) {
|
|
175
|
+
throw new Error(`Invalid WU ID format: ${wuId}. Expected format: WU-XXX (e.g., WU-1234)`);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Query ready nodes for a WU.
|
|
180
|
+
*
|
|
181
|
+
* Returns unblocked, open nodes linked to the WU in deterministic order:
|
|
182
|
+
* 1. Priority (P0 first, then P1, P2, P3; nodes without priority last)
|
|
183
|
+
* 2. CreatedAt (oldest first for same priority)
|
|
184
|
+
* 3. ID (alphabetical for stable sort)
|
|
185
|
+
*
|
|
186
|
+
* @param baseDir - Base directory containing .beacon/memory
|
|
187
|
+
* @param options - Query options
|
|
188
|
+
* @returns Deterministically ordered ready nodes
|
|
189
|
+
* @throws If WU ID format is invalid or file contains malformed JSON
|
|
190
|
+
*
|
|
191
|
+
* @example
|
|
192
|
+
* const ready = await queryReadyNodes('/path/to/project', { wuId: 'WU-1234' });
|
|
193
|
+
* console.log(`${ready.length} nodes ready for processing`);
|
|
194
|
+
*
|
|
195
|
+
* @example
|
|
196
|
+
* // Filter by type
|
|
197
|
+
* const discoveries = await queryReadyNodes('/path/to/project', {
|
|
198
|
+
* wuId: 'WU-1234',
|
|
199
|
+
* type: 'discovery',
|
|
200
|
+
* });
|
|
201
|
+
*/
|
|
202
|
+
export async function queryReadyNodes(baseDir, options) {
|
|
203
|
+
const { wuId, type } = options;
|
|
204
|
+
// Validate WU ID
|
|
205
|
+
validateWuId(wuId);
|
|
206
|
+
const memoryDir = path.join(baseDir, '.beacon', 'memory');
|
|
207
|
+
// Load memory and relationships
|
|
208
|
+
const memory = await loadMemory(memoryDir);
|
|
209
|
+
const relationships = await loadRelationships(memoryDir);
|
|
210
|
+
// Build set of blocked node IDs from relationships
|
|
211
|
+
const blockedByRelationships = buildBlockedSet(relationships);
|
|
212
|
+
// Get nodes for this WU
|
|
213
|
+
const wuNodes = memory.byWu.get(wuId) ?? [];
|
|
214
|
+
// Filter to ready nodes only
|
|
215
|
+
const readyNodes = wuNodes.filter((node) => {
|
|
216
|
+
// Exclude blocked nodes
|
|
217
|
+
if (isBlocked(node, blockedByRelationships)) {
|
|
218
|
+
return false;
|
|
219
|
+
}
|
|
220
|
+
// Exclude closed nodes
|
|
221
|
+
if (isClosed(node)) {
|
|
222
|
+
return false;
|
|
223
|
+
}
|
|
224
|
+
// Apply type filter if specified
|
|
225
|
+
if (type && node.type !== type) {
|
|
226
|
+
return false;
|
|
227
|
+
}
|
|
228
|
+
return true;
|
|
229
|
+
});
|
|
230
|
+
// Sort deterministically
|
|
231
|
+
return readyNodes.sort(compareNodes);
|
|
232
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mem-ready-core.js","sourceRoot":"","sources":["../src/mem-ready-core.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory Signal Core Logic (WU-1473)
|
|
3
|
+
*
|
|
4
|
+
* Core logic for creating coordination signals between parallel agents.
|
|
5
|
+
* Enables sub-100ms agent communication via JSONL append operations.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Append-only writes for sub-100ms performance
|
|
9
|
+
* - WU-scoped signals for focused coordination
|
|
10
|
+
* - Lane-targeted signals for cross-team communication
|
|
11
|
+
* - Read/unread tracking for mem:inbox integration
|
|
12
|
+
*
|
|
13
|
+
* @see {@link tools/mem-signal.mjs} - CLI wrapper
|
|
14
|
+
* @see {@link tools/__tests__/mem-signal.test.mjs} - Tests
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Signal file name constant
|
|
18
|
+
*/
|
|
19
|
+
export declare const SIGNAL_FILE_NAME = "signals.jsonl";
|
|
20
|
+
/**
|
|
21
|
+
* Signal structure
|
|
22
|
+
*/
|
|
23
|
+
export interface Signal {
|
|
24
|
+
/** Unique signal identifier (sig-XXXXXXXX) */
|
|
25
|
+
id: string;
|
|
26
|
+
/** Signal content/message */
|
|
27
|
+
message: string;
|
|
28
|
+
/** ISO 8601 timestamp */
|
|
29
|
+
created_at: string;
|
|
30
|
+
/** Whether signal has been read */
|
|
31
|
+
read: boolean;
|
|
32
|
+
/** Optional WU ID scope */
|
|
33
|
+
wu_id?: string;
|
|
34
|
+
/** Optional target lane */
|
|
35
|
+
lane?: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Result of creating a signal
|
|
39
|
+
*/
|
|
40
|
+
export interface CreateSignalResult {
|
|
41
|
+
/** Whether signal was created successfully */
|
|
42
|
+
success: boolean;
|
|
43
|
+
/** The created signal object */
|
|
44
|
+
signal: Signal;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Options for creating a signal
|
|
48
|
+
*/
|
|
49
|
+
export interface CreateSignalOptions {
|
|
50
|
+
/** Signal message content (required) */
|
|
51
|
+
message: string;
|
|
52
|
+
/** WU ID to scope signal to */
|
|
53
|
+
wuId?: string;
|
|
54
|
+
/** Lane to target signal to */
|
|
55
|
+
lane?: string;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Options for loading signals
|
|
59
|
+
*/
|
|
60
|
+
export interface LoadSignalsOptions {
|
|
61
|
+
/** Filter by WU ID */
|
|
62
|
+
wuId?: string;
|
|
63
|
+
/** Filter by lane */
|
|
64
|
+
lane?: string;
|
|
65
|
+
/** Only return unread signals */
|
|
66
|
+
unreadOnly?: boolean;
|
|
67
|
+
/** Only return signals created after this time */
|
|
68
|
+
since?: Date | string;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Result of marking signals as read
|
|
72
|
+
*/
|
|
73
|
+
export interface MarkAsReadResult {
|
|
74
|
+
/** Number of signals marked as read */
|
|
75
|
+
markedCount: number;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Creates a coordination signal between parallel agents.
|
|
79
|
+
*
|
|
80
|
+
* Signals are appended to signals.jsonl using append-only writes
|
|
81
|
+
* for sub-100ms performance. Signals can be scoped to a specific
|
|
82
|
+
* WU or targeted at a specific lane.
|
|
83
|
+
*
|
|
84
|
+
* @param {string} baseDir - Project base directory
|
|
85
|
+
* @param {CreateSignalOptions} options - Signal options
|
|
86
|
+
* @returns {Promise<CreateSignalResult>} Result with created signal
|
|
87
|
+
* @throws {Error} If message is missing or WU ID is invalid
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* const result = await createSignal('/project', {
|
|
91
|
+
* message: 'Starting feature implementation',
|
|
92
|
+
* wuId: 'WU-1473',
|
|
93
|
+
* lane: 'Operations: Tooling',
|
|
94
|
+
* });
|
|
95
|
+
*/
|
|
96
|
+
export declare function createSignal(baseDir: string, options: CreateSignalOptions): Promise<CreateSignalResult>;
|
|
97
|
+
/**
|
|
98
|
+
* Loads signals from the signals file with optional filtering.
|
|
99
|
+
*
|
|
100
|
+
* Signals are returned in chronological order (oldest first).
|
|
101
|
+
* Supports filtering by WU ID, lane, and read status.
|
|
102
|
+
*
|
|
103
|
+
* @param {string} baseDir - Project base directory
|
|
104
|
+
* @param {LoadSignalsOptions} [options={}] - Filter options
|
|
105
|
+
* @returns {Promise<Signal[]>} Array of signals matching filters
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* // Load all signals
|
|
109
|
+
* const all = await loadSignals('/project');
|
|
110
|
+
*
|
|
111
|
+
* // Load unread signals for a specific WU
|
|
112
|
+
* const unread = await loadSignals('/project', {
|
|
113
|
+
* wuId: 'WU-1473',
|
|
114
|
+
* unreadOnly: true,
|
|
115
|
+
* });
|
|
116
|
+
*/
|
|
117
|
+
export declare function loadSignals(baseDir: string, options?: LoadSignalsOptions): Promise<Signal[]>;
|
|
118
|
+
/**
|
|
119
|
+
* Marks signals as read by updating the signals file.
|
|
120
|
+
*
|
|
121
|
+
* Reads the entire file, updates the read status for matching IDs,
|
|
122
|
+
* and writes back. Only signals that were previously unread are counted.
|
|
123
|
+
*
|
|
124
|
+
* @param baseDir - Project base directory
|
|
125
|
+
* @param signalIds - Array of signal IDs to mark as read
|
|
126
|
+
* @returns Result with count of signals marked
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* const result = await markSignalsAsRead('/project', ['sig-abc12345', 'sig-def67890']);
|
|
130
|
+
* console.log(result.markedCount); // 2
|
|
131
|
+
*/
|
|
132
|
+
export declare function markSignalsAsRead(baseDir: string, signalIds: string[]): Promise<MarkAsReadResult>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mem-signal-core.d.ts","sourceRoot":"","sources":["../src/mem-signal-core.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAMH;;GAEG;AACH,eAAO,MAAM,gBAAgB,kBAAkB,CAAC;AA8GhD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,YAAY,CAAC,OAAO,KAAA,EAAE,OAAO,KAAA;;;;;;;;GA4ClD;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,WAAW,CAAC,OAAO,KAAA,EAAE,OAAO,KAAK,gBA2CtD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,KAAA,EAAE,SAAS,KAAA;;GAkCzD"}
|