la-machina-engine 0.4.0 → 0.5.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/README.md +28 -1
- package/dist/index.cjs +28 -39
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +38 -20
- package/dist/index.d.ts +38 -20
- package/dist/index.js +28 -39
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -495,7 +495,7 @@ engine.run({ runId, nodeId, task })
|
|
|
495
495
|
|
|
496
496
|
### Storage Adapter
|
|
497
497
|
|
|
498
|
-
|
|
498
|
+
Three backends, same interface and the same relative layout on all of them:
|
|
499
499
|
|
|
500
500
|
| Adapter | Backend | Use |
|
|
501
501
|
|---------|---------|-----|
|
|
@@ -503,6 +503,33 @@ Two backends, same interface:
|
|
|
503
503
|
| `R2StorageAdapter` | Cloudflare R2 via S3 protocol | Node / anywhere with S3 creds |
|
|
504
504
|
| `R2BindingStorageAdapter` | Cloudflare R2 native binding (`env.BUCKET`) | Cloudflare Workers (`provider: 'r2-binding'`) |
|
|
505
505
|
|
|
506
|
+
**Path layout (identical across all three backends):**
|
|
507
|
+
|
|
508
|
+
```
|
|
509
|
+
{rootPath}/workspaces/{workspaceId}/.claude/ ← tenant root
|
|
510
|
+
├── memory/ ← tenant-shared, survives across runs
|
|
511
|
+
├── skills/ ← (if config.skills.autoload)
|
|
512
|
+
└── projects/{runId}/nodes/{nodeId}/
|
|
513
|
+
├── state.json, snapshot.json, 000000.jsonl, meta.json
|
|
514
|
+
└── subagents/{agentId}/… ← recursive, same shape
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
`workspaces/` is a namespace guard (keeps engine data separate from
|
|
518
|
+
anything else in a shared bucket/filesystem); `.claude/` marks
|
|
519
|
+
engine-owned content. Both cost one directory level each.
|
|
520
|
+
|
|
521
|
+
**The workspace IS the tenant boundary.** One `workspaceId` per
|
|
522
|
+
tenant; nothing is shared across workspaces. The previous
|
|
523
|
+
`global` storage scope was removed in v0.5.0 — see migration note
|
|
524
|
+
below.
|
|
525
|
+
|
|
526
|
+
> **Migration from pre-0.5.0**: if you had data at `{rootPath}/.claude/`
|
|
527
|
+
> (the old global scope), move it under your workspace root:
|
|
528
|
+
> `mv {rootPath}/.claude {rootPath}/workspaces/{workspaceId}/.claude`.
|
|
529
|
+
> `config.memory.scope: 'global'` still parses but emits a
|
|
530
|
+
> deprecation warning and is rewritten to `'workspace'`; it'll be
|
|
531
|
+
> rejected outright in v1.0.0.
|
|
532
|
+
|
|
506
533
|
### Smart Memory
|
|
507
534
|
|
|
508
535
|
Per-workspace learning across runs:
|
package/dist/index.cjs
CHANGED
|
@@ -943,7 +943,8 @@ var ModelProviderEnum = import_zod.z.enum([
|
|
|
943
943
|
]);
|
|
944
944
|
var StorageProviderEnum = import_zod.z.enum(["local", "r2", "r2-binding"]);
|
|
945
945
|
var MemoryModeEnum = import_zod.z.enum(["off", "read-only", "read-write"]);
|
|
946
|
-
var
|
|
946
|
+
var MemoryScopeUserEnum = import_zod.z.enum(["workspace", "global"]);
|
|
947
|
+
var MemoryScopeResolvedEnum = import_zod.z.enum(["workspace"]);
|
|
947
948
|
var FlushPolicyEnum = import_zod.z.enum(["turn-end", "entry", "manual"]);
|
|
948
949
|
var LogLevelEnum = import_zod.z.enum(["silent", "error", "warn", "info", "debug"]);
|
|
949
950
|
var R2ConfigResolved = import_zod.z.object({
|
|
@@ -982,7 +983,7 @@ var StorageConfigResolved = import_zod.z.object({
|
|
|
982
983
|
});
|
|
983
984
|
var MemoryConfigResolved = import_zod.z.object({
|
|
984
985
|
mode: MemoryModeEnum,
|
|
985
|
-
scope:
|
|
986
|
+
scope: MemoryScopeResolvedEnum
|
|
986
987
|
}).strict();
|
|
987
988
|
var ToolsConfigResolved = import_zod.z.object({
|
|
988
989
|
enabled: import_zod.z.array(import_zod.z.string()),
|
|
@@ -1177,7 +1178,10 @@ var StorageConfigUser = import_zod.z.object({
|
|
|
1177
1178
|
r2: R2ConfigUser.optional(),
|
|
1178
1179
|
r2Binding: R2BucketBindingShape.optional()
|
|
1179
1180
|
}).strict();
|
|
1180
|
-
var MemoryConfigUser =
|
|
1181
|
+
var MemoryConfigUser = import_zod.z.object({
|
|
1182
|
+
mode: MemoryModeEnum.optional(),
|
|
1183
|
+
scope: MemoryScopeUserEnum.optional()
|
|
1184
|
+
}).strict();
|
|
1181
1185
|
var ToolsConfigUser = ToolsConfigResolved.partial();
|
|
1182
1186
|
var AgentsConfigUser = AgentsConfigResolved.partial();
|
|
1183
1187
|
var SkillsConfigUser = SkillsConfigResolved.partial();
|
|
@@ -1290,8 +1294,21 @@ function splitApiRuntime(user) {
|
|
|
1290
1294
|
const clone = { ...user, api: schemaSafe };
|
|
1291
1295
|
return { stripped: clone, runtime };
|
|
1292
1296
|
}
|
|
1297
|
+
function coerceDeprecatedMemoryScope(user) {
|
|
1298
|
+
const scope = user.memory?.scope;
|
|
1299
|
+
if (scope !== "global") return user;
|
|
1300
|
+
console.warn(
|
|
1301
|
+
'[la-machina] config.memory.scope: "global" is deprecated and has been rewritten to "workspace". Cross-tenant memory sharing was removed in Plan 022 \u2014 the workspace is the tenant root. This field value will be rejected outright in a future major release.'
|
|
1302
|
+
);
|
|
1303
|
+
const memory = user.memory ?? {};
|
|
1304
|
+
return {
|
|
1305
|
+
...user,
|
|
1306
|
+
memory: { ...memory, scope: "workspace" }
|
|
1307
|
+
};
|
|
1308
|
+
}
|
|
1293
1309
|
function mergeConfig(user) {
|
|
1294
|
-
const
|
|
1310
|
+
const withCoercedScope = coerceDeprecatedMemoryScope(user);
|
|
1311
|
+
const { stripped, runtime } = splitApiRuntime(withCoercedScope);
|
|
1295
1312
|
const validatedUser = UserConfigSchema.parse(stripped);
|
|
1296
1313
|
const merged = deepMerge(DEFAULTS, validatedUser);
|
|
1297
1314
|
const resolved = ResolvedConfigSchema.parse(merged);
|
|
@@ -7165,7 +7182,7 @@ ${entries.map((e) => `- ${e}`).join("\n")}
|
|
|
7165
7182
|
// src/memory/memoryConfig.ts
|
|
7166
7183
|
function createSmartMemory(options) {
|
|
7167
7184
|
const { storage, config } = options;
|
|
7168
|
-
const adapter =
|
|
7185
|
+
const adapter = storage.workspace;
|
|
7169
7186
|
const hippocampus = new Hippocampus(adapter, "smart-memory");
|
|
7170
7187
|
const writesEnabled = config.mode === "read-write";
|
|
7171
7188
|
const readsEnabled = config.mode !== "off";
|
|
@@ -7536,18 +7553,7 @@ ${lessons}`);
|
|
|
7536
7553
|
}
|
|
7537
7554
|
async function collectSkills(storage, skillsDir) {
|
|
7538
7555
|
const workspace = await loadSkills(storage.workspace, skillsDir);
|
|
7539
|
-
|
|
7540
|
-
const seen = /* @__PURE__ */ new Set();
|
|
7541
|
-
const out = [];
|
|
7542
|
-
for (const s of workspace) {
|
|
7543
|
-
seen.add(s.name);
|
|
7544
|
-
out.push({ name: s.name, description: s.description });
|
|
7545
|
-
}
|
|
7546
|
-
for (const s of global) {
|
|
7547
|
-
if (seen.has(s.name)) continue;
|
|
7548
|
-
out.push({ name: s.name, description: s.description });
|
|
7549
|
-
}
|
|
7550
|
-
return out;
|
|
7556
|
+
return workspace.map((s) => ({ name: s.name, description: s.description }));
|
|
7551
7557
|
}
|
|
7552
7558
|
|
|
7553
7559
|
// src/engine/jsonOutput.ts
|
|
@@ -7881,14 +7887,8 @@ var StorageSkillSource = class {
|
|
|
7881
7887
|
this.baseDir = options.baseDir ?? "skills";
|
|
7882
7888
|
}
|
|
7883
7889
|
async list() {
|
|
7884
|
-
const
|
|
7885
|
-
|
|
7886
|
-
loadSkills(this.storage.global, this.baseDir)
|
|
7887
|
-
]);
|
|
7888
|
-
const byName = /* @__PURE__ */ new Map();
|
|
7889
|
-
for (const s of global) byName.set(s.name, s);
|
|
7890
|
-
for (const s of workspace) byName.set(s.name, s);
|
|
7891
|
-
return Array.from(byName.values()).map((s) => ({
|
|
7890
|
+
const loaded = await loadSkills(this.storage.workspace, this.baseDir);
|
|
7891
|
+
return loaded.map((s) => ({
|
|
7892
7892
|
name: s.name,
|
|
7893
7893
|
description: s.description,
|
|
7894
7894
|
hasPages: s.hasPages
|
|
@@ -7896,8 +7896,7 @@ var StorageSkillSource = class {
|
|
|
7896
7896
|
}
|
|
7897
7897
|
async getSkillFile(skill) {
|
|
7898
7898
|
if (!SAFE_NAME4.test(skill)) return null;
|
|
7899
|
-
|
|
7900
|
-
return found;
|
|
7899
|
+
return this.findFile(skill, "SKILL.md");
|
|
7901
7900
|
}
|
|
7902
7901
|
async getPage(skill, page) {
|
|
7903
7902
|
if (!SAFE_NAME4.test(skill)) return null;
|
|
@@ -7906,9 +7905,7 @@ var StorageSkillSource = class {
|
|
|
7906
7905
|
}
|
|
7907
7906
|
async listPages(skill) {
|
|
7908
7907
|
if (!SAFE_NAME4.test(skill)) return [];
|
|
7909
|
-
|
|
7910
|
-
if (wsPages.length > 0) return wsPages;
|
|
7911
|
-
return this.listPagesIn(this.storage.global, skill);
|
|
7908
|
+
return this.listPagesIn(this.storage.workspace, skill);
|
|
7912
7909
|
}
|
|
7913
7910
|
async listPagesIn(adapter, skill) {
|
|
7914
7911
|
const pagesDir = `${this.baseDir}/${skill}/pages`;
|
|
@@ -7921,9 +7918,7 @@ var StorageSkillSource = class {
|
|
|
7921
7918
|
}
|
|
7922
7919
|
async findFile(skill, relative) {
|
|
7923
7920
|
const path = `${this.baseDir}/${skill}/${relative}`;
|
|
7924
|
-
|
|
7925
|
-
if (fromWorkspace !== null) return fromWorkspace;
|
|
7926
|
-
return this.readIfExists(this.storage.global, path);
|
|
7921
|
+
return this.readIfExists(this.storage.workspace, path);
|
|
7927
7922
|
}
|
|
7928
7923
|
async readIfExists(adapter, path) {
|
|
7929
7924
|
try {
|
|
@@ -8506,7 +8501,6 @@ async function createEngineStorage(config) {
|
|
|
8506
8501
|
}
|
|
8507
8502
|
async function createLocalStorage(config) {
|
|
8508
8503
|
const path = await import("path");
|
|
8509
|
-
const globalRoot = path.join(config.rootPath, ENGINE_DATA_FOLDER);
|
|
8510
8504
|
const workspaceRoot = path.join(
|
|
8511
8505
|
config.rootPath,
|
|
8512
8506
|
WORKSPACES_FOLDER,
|
|
@@ -8514,7 +8508,6 @@ async function createLocalStorage(config) {
|
|
|
8514
8508
|
ENGINE_DATA_FOLDER
|
|
8515
8509
|
);
|
|
8516
8510
|
return {
|
|
8517
|
-
global: new LocalStorageAdapter(globalRoot),
|
|
8518
8511
|
workspace: new LocalStorageAdapter(workspaceRoot)
|
|
8519
8512
|
};
|
|
8520
8513
|
}
|
|
@@ -8523,10 +8516,8 @@ function createR2Storage(config) {
|
|
|
8523
8516
|
throw new StorageError('storage.r2 is required when storage.provider === "r2"');
|
|
8524
8517
|
}
|
|
8525
8518
|
const rootPrefix = config.rootPath.replace(/^\/+|\/+$/g, "");
|
|
8526
|
-
const globalPrefix = `${rootPrefix}/${ENGINE_DATA_FOLDER}`;
|
|
8527
8519
|
const workspacePrefix = `${rootPrefix}/${WORKSPACES_FOLDER}/${config.workspaceId}/${ENGINE_DATA_FOLDER}`;
|
|
8528
8520
|
return {
|
|
8529
|
-
global: new R2StorageAdapter(config.r2, globalPrefix),
|
|
8530
8521
|
workspace: new R2StorageAdapter(config.r2, workspacePrefix)
|
|
8531
8522
|
};
|
|
8532
8523
|
}
|
|
@@ -8535,10 +8526,8 @@ function createR2BindingStorage(config) {
|
|
|
8535
8526
|
throw new StorageError('storage.r2Binding is required when storage.provider === "r2-binding"');
|
|
8536
8527
|
}
|
|
8537
8528
|
const rootPrefix = config.rootPath.replace(/^\/+|\/+$/g, "");
|
|
8538
|
-
const globalPrefix = `${rootPrefix}/${ENGINE_DATA_FOLDER}`;
|
|
8539
8529
|
const workspacePrefix = `${rootPrefix}/${WORKSPACES_FOLDER}/${config.workspaceId}/${ENGINE_DATA_FOLDER}`;
|
|
8540
8530
|
return {
|
|
8541
|
-
global: new R2BindingStorageAdapter(config.r2Binding, globalPrefix),
|
|
8542
8531
|
workspace: new R2BindingStorageAdapter(config.r2Binding, workspacePrefix)
|
|
8543
8532
|
};
|
|
8544
8533
|
}
|