@rubytech/taskmaster 1.0.89 → 1.0.90
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/dist/build-info.json +2 -2
- package/dist/memory/internal.js +16 -0
- package/dist/memory/layout.js +69 -4
- package/package.json +1 -1
package/dist/build-info.json
CHANGED
package/dist/memory/internal.js
CHANGED
|
@@ -34,6 +34,22 @@ async function walkDir(dir, files) {
|
|
|
34
34
|
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
35
35
|
for (const entry of entries) {
|
|
36
36
|
const full = path.join(dir, entry.name);
|
|
37
|
+
// Symlinks need fs.stat to determine the target type
|
|
38
|
+
if (entry.isSymbolicLink()) {
|
|
39
|
+
try {
|
|
40
|
+
const stat = await fs.stat(full);
|
|
41
|
+
if (stat.isDirectory()) {
|
|
42
|
+
await walkDir(full, files);
|
|
43
|
+
}
|
|
44
|
+
else if (stat.isFile() && entry.name.endsWith(".md")) {
|
|
45
|
+
files.push(full);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
// Broken symlink — skip
|
|
50
|
+
}
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
37
53
|
if (entry.isDirectory()) {
|
|
38
54
|
await walkDir(full, files);
|
|
39
55
|
continue;
|
package/dist/memory/layout.js
CHANGED
|
@@ -25,6 +25,8 @@ import { createSubsystemLogger } from "../logging/subsystem.js";
|
|
|
25
25
|
const log = createSubsystemLogger("memory-layout");
|
|
26
26
|
/** Shared scope folders symlinked from each agent workspace. */
|
|
27
27
|
const SHARED_FOLDERS = ["public", "shared"];
|
|
28
|
+
/** Agent-specific folders that belong in per-agent memory, not at the shared root. */
|
|
29
|
+
const AGENT_SPECIFIC_FOLDERS = ["admin", "users", "groups"];
|
|
28
30
|
/** The relative symlink target from agents/{id}/memory/{scope} → ../../../memory/{scope} */
|
|
29
31
|
const SYMLINK_TARGET_PREFIX = "../../../memory";
|
|
30
32
|
async function exists(p) {
|
|
@@ -139,6 +141,7 @@ export async function ensureMemoryLayout(workspaceRoot, agentDirs) {
|
|
|
139
141
|
await fs.mkdir(path.join(memoryPath, "admin"), { recursive: true });
|
|
140
142
|
}
|
|
141
143
|
await fs.mkdir(path.join(memoryPath, "users"), { recursive: true });
|
|
144
|
+
await fs.mkdir(path.join(memoryPath, "groups"), { recursive: true });
|
|
142
145
|
// Remove admin/ from non-admin agent workspaces (it should never exist there)
|
|
143
146
|
if (!isAdmin) {
|
|
144
147
|
const adminPath = path.join(memoryPath, "admin");
|
|
@@ -147,13 +150,75 @@ export async function ensureMemoryLayout(workspaceRoot, agentDirs) {
|
|
|
147
150
|
await fs.rm(adminPath, { recursive: true }).catch(() => { });
|
|
148
151
|
}
|
|
149
152
|
else {
|
|
150
|
-
log.warn(`non-admin agent has data in memory/admin/ — moving to
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
153
|
+
log.warn(`non-admin agent has data in memory/admin/ — moving to admin agent`);
|
|
154
|
+
// Find admin agent dir and merge there
|
|
155
|
+
const adminAgent = agentDirs.find((a) => a.id.toLowerCase() === "admin" || a.id.toLowerCase().endsWith("-admin"));
|
|
156
|
+
if (adminAgent) {
|
|
157
|
+
const adminMemAdmin = path.join(adminAgent.dir, "memory", "admin");
|
|
158
|
+
await fs.mkdir(adminMemAdmin, { recursive: true });
|
|
159
|
+
await mergeDir(adminPath, adminMemAdmin);
|
|
160
|
+
}
|
|
154
161
|
await fs.rm(adminPath, { recursive: true }).catch(() => { });
|
|
155
162
|
}
|
|
156
163
|
}
|
|
157
164
|
}
|
|
158
165
|
}
|
|
166
|
+
// Sweep orphaned agent-specific data from the shared root.
|
|
167
|
+
// After full-symlink migration, admin/, users/, groups/, notes/, and loose files
|
|
168
|
+
// remain at ~/taskmaster/memory/ but are no longer accessible via per-subfolder symlinks.
|
|
169
|
+
// Move them to the admin agent's workspace (most privileged, owns historical data).
|
|
170
|
+
await migrateOrphanedSharedData(sharedMemoryDir, agentDirs);
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Move agent-specific data that was left at the shared memory root
|
|
174
|
+
* (from the old full-symlink layout) into the admin agent's workspace.
|
|
175
|
+
*
|
|
176
|
+
* Only `public/` and `shared/` belong at the shared root.
|
|
177
|
+
* Everything else is orphaned and needs to move to a per-agent location.
|
|
178
|
+
*/
|
|
179
|
+
async function migrateOrphanedSharedData(sharedMemoryDir, agentDirs) {
|
|
180
|
+
const adminAgent = agentDirs.find((a) => a.id.toLowerCase() === "admin" || a.id.toLowerCase().endsWith("-admin"));
|
|
181
|
+
if (!adminAgent)
|
|
182
|
+
return; // No admin agent — nothing to migrate to
|
|
183
|
+
const adminMemoryPath = path.join(adminAgent.dir, "memory");
|
|
184
|
+
let entries;
|
|
185
|
+
try {
|
|
186
|
+
entries = await fs.readdir(sharedMemoryDir);
|
|
187
|
+
}
|
|
188
|
+
catch {
|
|
189
|
+
return; // Shared dir doesn't exist
|
|
190
|
+
}
|
|
191
|
+
const sharedSet = new Set(SHARED_FOLDERS);
|
|
192
|
+
for (const name of entries) {
|
|
193
|
+
// Skip shared folders — they belong here
|
|
194
|
+
if (sharedSet.has(name))
|
|
195
|
+
continue;
|
|
196
|
+
// Skip .DS_Store and other hidden files
|
|
197
|
+
if (name.startsWith("."))
|
|
198
|
+
continue;
|
|
199
|
+
const srcPath = path.join(sharedMemoryDir, name);
|
|
200
|
+
if (await isDirectory(srcPath)) {
|
|
201
|
+
const destPath = path.join(adminMemoryPath, name);
|
|
202
|
+
if (await isEmptyDir(srcPath)) {
|
|
203
|
+
// Empty orphan dir — just remove it
|
|
204
|
+
await fs.rm(srcPath, { recursive: true }).catch(() => { });
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
// Merge into admin agent's workspace
|
|
208
|
+
log.info(`migrating orphaned ${name}/ from shared root to admin agent`);
|
|
209
|
+
await mergeDir(srcPath, destPath);
|
|
210
|
+
// Remove source if now empty
|
|
211
|
+
if (await isEmptyDir(srcPath)) {
|
|
212
|
+
await fs.rm(srcPath, { recursive: true }).catch(() => { });
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
else if (name.endsWith(".md")) {
|
|
216
|
+
// Loose .md files — move to admin agent's memory root
|
|
217
|
+
const destPath = path.join(adminMemoryPath, name);
|
|
218
|
+
if (!(await exists(destPath))) {
|
|
219
|
+
log.info(`migrating orphaned ${name} from shared root to admin agent`);
|
|
220
|
+
await fs.rename(srcPath, destPath);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
159
224
|
}
|