@framers/agentos 0.13.64 → 0.13.66
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/cognition/emergent/EmergentAgentForge.d.ts.map +1 -1
- package/dist/cognition/emergent/EmergentAgentForge.js +5 -4
- package/dist/cognition/emergent/EmergentAgentForge.js.map +1 -1
- package/dist/cognition/emergent/EmergentCapabilityEngine.d.ts +2 -0
- package/dist/cognition/emergent/EmergentCapabilityEngine.d.ts.map +1 -1
- package/dist/cognition/emergent/EmergentCapabilityEngine.js +10 -0
- package/dist/cognition/emergent/EmergentCapabilityEngine.js.map +1 -1
- package/dist/cognition/emergent/ForgeToolMetaTool.d.ts +4 -1
- package/dist/cognition/emergent/ForgeToolMetaTool.d.ts.map +1 -1
- package/dist/cognition/emergent/ForgeToolMetaTool.js +14 -1
- package/dist/cognition/emergent/ForgeToolMetaTool.js.map +1 -1
- package/dist/cognition/emergent/SkillExporter.d.ts +44 -3
- package/dist/cognition/emergent/SkillExporter.d.ts.map +1 -1
- package/dist/cognition/emergent/SkillExporter.js +124 -18
- package/dist/cognition/emergent/SkillExporter.js.map +1 -1
- package/dist/cognition/emergent/ToolName.d.ts +63 -0
- package/dist/cognition/emergent/ToolName.d.ts.map +1 -0
- package/dist/cognition/emergent/ToolName.js +79 -0
- package/dist/cognition/emergent/ToolName.js.map +1 -0
- package/dist/cognition/emergent/index.d.ts +3 -1
- package/dist/cognition/emergent/index.d.ts.map +1 -1
- package/dist/cognition/emergent/index.js +2 -1
- package/dist/cognition/emergent/index.js.map +1 -1
- package/dist/cognition/memory/AgentMemory.d.ts +4 -2
- package/dist/cognition/memory/AgentMemory.d.ts.map +1 -1
- package/dist/cognition/memory/AgentMemory.js +3 -1
- package/dist/cognition/memory/AgentMemory.js.map +1 -1
- package/dist/cognition/memory/core/types.d.ts +1 -1
- package/dist/cognition/memory/core/types.d.ts.map +1 -1
- package/dist/cognition/memory/index.d.ts +1 -1
- package/dist/cognition/memory/index.d.ts.map +1 -1
- package/dist/cognition/memory/index.js.map +1 -1
- package/dist/cognition/memory/io/MarkdownExporter.d.ts +53 -9
- package/dist/cognition/memory/io/MarkdownExporter.d.ts.map +1 -1
- package/dist/cognition/memory/io/MarkdownExporter.js +208 -15
- package/dist/cognition/memory/io/MarkdownExporter.js.map +1 -1
- package/dist/cognition/memory/io/ObsidianExporter.d.ts +6 -4
- package/dist/cognition/memory/io/ObsidianExporter.d.ts.map +1 -1
- package/dist/cognition/memory/io/ObsidianExporter.js +5 -3
- package/dist/cognition/memory/io/ObsidianExporter.js.map +1 -1
- package/dist/cognition/memory/io/facade/Memory.d.ts +15 -3
- package/dist/cognition/memory/io/facade/Memory.d.ts.map +1 -1
- package/dist/cognition/memory/io/facade/Memory.js +20 -8
- package/dist/cognition/memory/io/facade/Memory.js.map +1 -1
- package/dist/cognition/memory/io/facade/index.d.ts +1 -1
- package/dist/cognition/memory/io/facade/index.d.ts.map +1 -1
- package/dist/cognition/memory/io/facade/types.d.ts +41 -0
- package/dist/cognition/memory/io/facade/types.d.ts.map +1 -1
- package/dist/cognition/memory/io/tools/MemoryAddTool.d.ts +4 -0
- package/dist/cognition/memory/io/tools/MemoryAddTool.d.ts.map +1 -1
- package/dist/cognition/memory/io/tools/MemoryAddTool.js +18 -4
- package/dist/cognition/memory/io/tools/MemoryAddTool.js.map +1 -1
- package/dist/cognition/substrate/memory/wiki/WikiCompiler.d.ts +5 -1
- package/dist/cognition/substrate/memory/wiki/WikiCompiler.d.ts.map +1 -1
- package/dist/cognition/substrate/memory/wiki/WikiCompiler.js +35 -10
- package/dist/cognition/substrate/memory/wiki/WikiCompiler.js.map +1 -1
- package/dist/cognition/substrate/memory/wiki/WikiMemoryStore.d.ts +23 -4
- package/dist/cognition/substrate/memory/wiki/WikiMemoryStore.d.ts.map +1 -1
- package/dist/cognition/substrate/memory/wiki/WikiMemoryStore.js +66 -35
- package/dist/cognition/substrate/memory/wiki/WikiMemoryStore.js.map +1 -1
- package/dist/cognition/substrate/memory/wiki/WikiPageId.d.ts +9 -7
- package/dist/cognition/substrate/memory/wiki/WikiPageId.d.ts.map +1 -1
- package/dist/cognition/substrate/memory/wiki/WikiPageId.js +20 -32
- package/dist/cognition/substrate/memory/wiki/WikiPageId.js.map +1 -1
- package/dist/core/utils/linkFreeWrite.d.ts +66 -0
- package/dist/core/utils/linkFreeWrite.d.ts.map +1 -0
- package/dist/core/utils/linkFreeWrite.js +140 -0
- package/dist/core/utils/linkFreeWrite.js.map +1 -0
- package/dist/core/utils/pathName.d.ts +66 -0
- package/dist/core/utils/pathName.d.ts.map +1 -0
- package/dist/core/utils/pathName.js +91 -0
- package/dist/core/utils/pathName.js.map +1 -0
- package/package.json +1 -1
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
/** @fileoverview Folds new memory traces into wiki pages via LLM merge (merge-not-clobber). */
|
|
2
2
|
import { extractWikiLinks } from './WikiPageCodec.js';
|
|
3
3
|
import { assertWikiPageId, InvalidWikiPageIdError } from './WikiPageId.js';
|
|
4
|
+
/**
|
|
5
|
+
* The codes of file system errors that come from the paths a page write uses, so writing the same page fails the
|
|
6
|
+
* same way on every compile: a name the file system will not take (`ENAMETOOLONG`, `EINVAL`), a file where a folder
|
|
7
|
+
* must be (`ENOTDIR`, `EEXIST`), a folder where a file must be (`EISDIR`), or a loop of links (`ELOOP`).
|
|
8
|
+
*/
|
|
9
|
+
const PAGE_PATH_ERRORS = new Set(['ENAMETOOLONG', 'EINVAL', 'ENOTDIR', 'EEXIST', 'EISDIR', 'ELOOP']);
|
|
10
|
+
/** True for an error that writing the same page would raise again (see {@link PAGE_PATH_ERRORS}). */
|
|
11
|
+
function isPagePathError(err) {
|
|
12
|
+
const code = err instanceof Error ? err.code : undefined;
|
|
13
|
+
return typeof code === 'string' && PAGE_PATH_ERRORS.has(code);
|
|
14
|
+
}
|
|
4
15
|
const MERGE_PROMPT = (currentBody, facts) => `You maintain a knowledge wiki page. Here is the CURRENT page, which may include human edits:\n\n` +
|
|
5
16
|
`---\n${currentBody || '(empty page)'}\n---\n\n` +
|
|
6
17
|
`Integrate these NEW facts without discarding existing content. Preserve voice and structure. ` +
|
|
@@ -13,7 +24,11 @@ export class WikiCompiler {
|
|
|
13
24
|
/**
|
|
14
25
|
* Fold traces into the pages the cluster step assigns them to. An assignment whose page id the wiki
|
|
15
26
|
* refuses (see `isWikiPageId`) is not read, merged or written: it is reported in `conflicts`, with the
|
|
16
|
-
* reason as its note, and the other assignments go on.
|
|
27
|
+
* reason as its note, and the other assignments go on. An assignment whose page the file system refuses
|
|
28
|
+
* for its path, such as a name too long or a file where a folder must be, is reported there too: writing
|
|
29
|
+
* it would fail the same way on every compile. Its traces are not counted as consumed. Any other failed
|
|
30
|
+
* write, such as a full disk or a missing permission, rejects the compile, so a caller that keeps a
|
|
31
|
+
* watermark compiles the same traces again.
|
|
17
32
|
*/
|
|
18
33
|
async compile(input) {
|
|
19
34
|
const result = { pagesWritten: [], tracesConsumed: 0, conflicts: [] };
|
|
@@ -43,15 +58,25 @@ export class WikiCompiler {
|
|
|
43
58
|
const mergedBody = (await this.opts.llm(MERGE_PROMPT(current?.body ?? '', facts))).trim();
|
|
44
59
|
const type = current?.type ?? inferType(a.pageId);
|
|
45
60
|
const newSources = [...new Set([...(current?.sources ?? []), ...a.traceIds])];
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
61
|
+
try {
|
|
62
|
+
await this.opts.store.writePage({
|
|
63
|
+
id: a.pageId,
|
|
64
|
+
type,
|
|
65
|
+
summary: current?.summary ?? facts[0].slice(0, 120),
|
|
66
|
+
updated: now(),
|
|
67
|
+
sources: newSources,
|
|
68
|
+
body: mergedBody,
|
|
69
|
+
links: extractWikiLinks(mergedBody),
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
// A page the file system refuses for its path would stop every later compile at the same batch, so it is
|
|
74
|
+
// reported and the compile goes on. Any other failure may pass, so it stops the compile.
|
|
75
|
+
if (!isPagePathError(err))
|
|
76
|
+
throw err;
|
|
77
|
+
result.conflicts.push({ pageId: a.pageId, note: `write failed: ${err.message}` });
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
55
80
|
result.pagesWritten.push(a.pageId);
|
|
56
81
|
result.tracesConsumed += a.traceIds.length;
|
|
57
82
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WikiCompiler.js","sourceRoot":"","sources":["../../../../../src/cognition/substrate/memory/wiki/WikiCompiler.ts"],"names":[],"mappings":"AAAA,+FAA+F;AAC/F,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AA+B3E,MAAM,YAAY,GAAG,CAAC,WAAmB,EAAE,KAAe,EAAU,EAAE,CACpE,kGAAkG;IAClG,QAAQ,WAAW,IAAI,cAAc,WAAW;IAChD,+FAA+F;IAC/F,2EAA2E;IAC3E,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAExC,MAAM,OAAO,YAAY;IACvB,YAA6B,IAAyB;QAAzB,SAAI,GAAJ,IAAI,CAAqB;IAAG,CAAC;IAE1D
|
|
1
|
+
{"version":3,"file":"WikiCompiler.js","sourceRoot":"","sources":["../../../../../src/cognition/substrate/memory/wiki/WikiCompiler.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,23 @@
|
|
|
1
|
+
import * as path from 'node:path';
|
|
1
2
|
import type { WikiPage, MetaIndex, IndexResult } from './types.js';
|
|
3
|
+
/** One entry of a folder's listing: its name, and whether it is a folder. `fs.Dirent` has this shape. */
|
|
4
|
+
export interface WikiFolderEntry {
|
|
5
|
+
name: string;
|
|
6
|
+
isDirectory(): boolean;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* List the page ids under `memoryDir`: each `.md` file's path under the folder without `.md`, with `/` between
|
|
10
|
+
* folders on every platform, the form the compiler writes and `readPage` takes. Every file or folder whose name
|
|
11
|
+
* starts with a dot (`.meta/` among them) is skipped, and so is every file whose path makes no valid page id,
|
|
12
|
+
* `index.md` among them, so every id listed is one `readPage` accepts.
|
|
13
|
+
*
|
|
14
|
+
* @param memoryDir - The wiki's folder.
|
|
15
|
+
* @param readDir - Lists one folder, given its path. A folder it cannot list is skipped.
|
|
16
|
+
* @param paths - The path functions that build a folder's path from `memoryDir` and its names: the platform's by
|
|
17
|
+
* default.
|
|
18
|
+
* @returns The ids, sorted.
|
|
19
|
+
*/
|
|
20
|
+
export declare function listWikiPageIds(memoryDir: string, readDir: (dir: string) => Promise<readonly WikiFolderEntry[]>, paths?: Pick<path.PlatformPath, 'join'>): Promise<string[]>;
|
|
2
21
|
/** The slice of the Memory facade the store depends on (injected for testability). */
|
|
3
22
|
export interface MemoryIndexPort {
|
|
4
23
|
remember(content: string, options?: Record<string, unknown>): Promise<{
|
|
@@ -42,12 +61,12 @@ export declare class WikiMemoryStore {
|
|
|
42
61
|
writePage(page: WikiPage): Promise<void>;
|
|
43
62
|
getCatalog(): Promise<string>;
|
|
44
63
|
private refreshCatalog;
|
|
64
|
+
/** The page ids under memory/ (see `listWikiPageIds`). */
|
|
65
|
+
private listPageIds;
|
|
45
66
|
/**
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
* does not make a valid page id is not a page, so every id listed is one `readPage` accepts.
|
|
67
|
+
* Read `.meta/index.json`, or an empty index when it is missing or unreadable. Its page entries are held in an
|
|
68
|
+
* object with no prototype (see `pageEntries`), so any page id is safe to look up.
|
|
49
69
|
*/
|
|
50
|
-
private listPageIds;
|
|
51
70
|
protected readMeta(): Promise<MetaIndex>;
|
|
52
71
|
protected writeMeta(meta: MetaIndex): Promise<void>;
|
|
53
72
|
/** Incremental: re-embed only pages whose body hash changed since the last index. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WikiMemoryStore.d.ts","sourceRoot":"","sources":["../../../../../src/cognition/substrate/memory/wiki/WikiMemoryStore.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"WikiMemoryStore.d.ts","sourceRoot":"","sources":["../../../../../src/cognition/substrate/memory/wiki/WikiMemoryStore.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAIlC,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEnE,yGAAyG;AACzG,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,IAAI,OAAO,CAAC;CACxB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,eAAe,CACnC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,eAAe,EAAE,CAAC,EAC7D,KAAK,GAAE,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,MAAM,CAAQ,GAC5C,OAAO,CAAC,MAAM,EAAE,CAAC,CAsBnB;AAkBD,sFAAsF;AACtF,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACtF,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC9C;AAED,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,eAAe,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAkB;IACvC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,IAAI,EAAE,sBAAsB;IAMxC;;;;;OAKG;IACH,OAAO,CAAC,QAAQ;IAIhB,qHAAqH;IAC/G,IAAI,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;IAUjC;;;;OAIG;IACG,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;IAUpD;;;;OAIG;IACG,SAAS,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAOxC,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;YAQrB,cAAc;IAK5B,0DAA0D;YAC5C,WAAW;IAIzB;;;OAGG;cACa,QAAQ,IAAI,OAAO,CAAC,SAAS,CAAC;cAY9B,SAAS,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAMzD,qFAAqF;IAC/E,KAAK,CAAC,IAAI,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,WAAW,CAAC;IAkD7D,gEAAgE;IAC1D,YAAY,IAAI,OAAO,CAAC,WAAW,CAAC;IAS1C,yEAAyE;IACnE,iBAAiB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAIjD,gEAAgE;IAC1D,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMpD,SAAS,KAAK,QAAQ,IAAI,MAAM,CAE/B;IACD,SAAS,KAAK,KAAK,IAAI,eAAe,CAErC;CACF"}
|
|
@@ -4,6 +4,61 @@ import * as path from 'node:path';
|
|
|
4
4
|
import { createHash } from 'node:crypto';
|
|
5
5
|
import { parsePage, serializePage, renderCatalog } from './WikiPageCodec.js';
|
|
6
6
|
import { isWikiPageId, resolveWikiPagePath } from './WikiPageId.js';
|
|
7
|
+
/**
|
|
8
|
+
* List the page ids under `memoryDir`: each `.md` file's path under the folder without `.md`, with `/` between
|
|
9
|
+
* folders on every platform, the form the compiler writes and `readPage` takes. Every file or folder whose name
|
|
10
|
+
* starts with a dot (`.meta/` among them) is skipped, and so is every file whose path makes no valid page id,
|
|
11
|
+
* `index.md` among them, so every id listed is one `readPage` accepts.
|
|
12
|
+
*
|
|
13
|
+
* @param memoryDir - The wiki's folder.
|
|
14
|
+
* @param readDir - Lists one folder, given its path. A folder it cannot list is skipped.
|
|
15
|
+
* @param paths - The path functions that build a folder's path from `memoryDir` and its names: the platform's by
|
|
16
|
+
* default.
|
|
17
|
+
* @returns The ids, sorted.
|
|
18
|
+
*/
|
|
19
|
+
export async function listWikiPageIds(memoryDir, readDir, paths = path) {
|
|
20
|
+
const out = [];
|
|
21
|
+
const walk = async (names) => {
|
|
22
|
+
let entries;
|
|
23
|
+
try {
|
|
24
|
+
entries = await readDir(paths.join(memoryDir, ...names));
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
for (const e of entries) {
|
|
30
|
+
if (e.name.startsWith('.'))
|
|
31
|
+
continue;
|
|
32
|
+
if (e.isDirectory()) {
|
|
33
|
+
await walk([...names, e.name]);
|
|
34
|
+
}
|
|
35
|
+
else if (e.name.endsWith('.md')) {
|
|
36
|
+
// Ids join folders with `/` on every platform, never with the platform's separator.
|
|
37
|
+
const id = [...names, e.name.slice(0, -3)].join('/');
|
|
38
|
+
if (isWikiPageId(id))
|
|
39
|
+
out.push(id);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
await walk([]);
|
|
44
|
+
return out.sort();
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* The page entries of `.meta/index.json` in an object with no prototype, so a page id that names a member every
|
|
48
|
+
* object has (`constructor`, `toString`, `__proto__`) finds only its own entry. An entry with no list of trace ids
|
|
49
|
+
* is dropped, and its page is indexed again.
|
|
50
|
+
*/
|
|
51
|
+
function pageEntries(pages) {
|
|
52
|
+
const entries = Object.create(null);
|
|
53
|
+
if (pages === null || typeof pages !== 'object' || Array.isArray(pages))
|
|
54
|
+
return entries;
|
|
55
|
+
for (const [id, entry] of Object.entries(pages)) {
|
|
56
|
+
if (entry !== null && typeof entry === 'object' && Array.isArray(entry.traceIds)) {
|
|
57
|
+
entries[id] = entry;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return entries;
|
|
61
|
+
}
|
|
7
62
|
export class WikiMemoryStore {
|
|
8
63
|
constructor(opts) {
|
|
9
64
|
this.memoryDir = opts.memoryDir;
|
|
@@ -68,48 +123,24 @@ export class WikiMemoryStore {
|
|
|
68
123
|
const pages = await this.load();
|
|
69
124
|
await fs.writeFile(path.join(this.memoryDir, 'index.md'), renderCatalog(pages));
|
|
70
125
|
}
|
|
71
|
-
/**
|
|
72
|
-
* Recursively list page ids (the path under memory/ with `/` between folders, no extension), skipping
|
|
73
|
-
* index.md and every file or folder whose name starts with a dot (`.meta/` among them). A file whose path
|
|
74
|
-
* does not make a valid page id is not a page, so every id listed is one `readPage` accepts.
|
|
75
|
-
*/
|
|
126
|
+
/** The page ids under memory/ (see `listWikiPageIds`). */
|
|
76
127
|
async listPageIds() {
|
|
77
|
-
|
|
78
|
-
const walk = async (relDir) => {
|
|
79
|
-
const abs = path.join(this.memoryDir, relDir);
|
|
80
|
-
let entries;
|
|
81
|
-
try {
|
|
82
|
-
entries = await fs.readdir(abs, { withFileTypes: true });
|
|
83
|
-
}
|
|
84
|
-
catch {
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
for (const e of entries) {
|
|
88
|
-
if (e.name.startsWith('.'))
|
|
89
|
-
continue;
|
|
90
|
-
// Ids join folders with `/` on every platform, the form the compiler writes and readPage takes.
|
|
91
|
-
const rel = relDir ? `${relDir}/${e.name}` : e.name;
|
|
92
|
-
if (e.isDirectory()) {
|
|
93
|
-
await walk(rel);
|
|
94
|
-
}
|
|
95
|
-
else if (e.name.endsWith('.md') && rel !== 'index.md') {
|
|
96
|
-
const id = rel.slice(0, -3);
|
|
97
|
-
if (isWikiPageId(id))
|
|
98
|
-
out.push(id);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
};
|
|
102
|
-
await walk('');
|
|
103
|
-
return out.sort();
|
|
128
|
+
return listWikiPageIds(this.memoryDir, (dir) => fs.readdir(dir, { withFileTypes: true }));
|
|
104
129
|
}
|
|
130
|
+
/**
|
|
131
|
+
* Read `.meta/index.json`, or an empty index when it is missing or unreadable. Its page entries are held in an
|
|
132
|
+
* object with no prototype (see `pageEntries`), so any page id is safe to look up.
|
|
133
|
+
*/
|
|
105
134
|
async readMeta() {
|
|
135
|
+
let parsed = null;
|
|
106
136
|
try {
|
|
107
|
-
|
|
108
|
-
return JSON.parse(raw);
|
|
137
|
+
parsed = JSON.parse(await fs.readFile(path.join(this.memoryDir, '.meta', 'index.json'), 'utf8'));
|
|
109
138
|
}
|
|
110
139
|
catch {
|
|
111
|
-
|
|
140
|
+
// No index yet, or one that does not parse: start from an empty one.
|
|
112
141
|
}
|
|
142
|
+
const meta = parsed !== null && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : {};
|
|
143
|
+
return { ...meta, lastCompiledAt: meta.lastCompiledAt ?? null, pages: pageEntries(meta.pages) };
|
|
113
144
|
}
|
|
114
145
|
async writeMeta(meta) {
|
|
115
146
|
const metaDir = path.join(this.memoryDir, '.meta');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WikiMemoryStore.js","sourceRoot":"","sources":["../../../../../src/cognition/substrate/memory/wiki/WikiMemoryStore.ts"],"names":[],"mappings":"AAAA,kGAAkG;AAClG,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAC7E,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"WikiMemoryStore.js","sourceRoot":"","sources":["../../../../../src/cognition/substrate/memory/wiki/WikiMemoryStore.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,9 +6,11 @@ export declare const MAX_WIKI_PAGE_ID_LENGTH = 512;
|
|
|
6
6
|
* Why a wiki page id was refused:
|
|
7
7
|
* - `'type'`: the id is not a string.
|
|
8
8
|
* - `'empty'`: the id is an empty string.
|
|
9
|
-
* - `'length'`: the id is longer than {@link MAX_WIKI_PAGE_ID_LENGTH} characters
|
|
10
|
-
* -
|
|
11
|
-
*
|
|
9
|
+
* - `'length'`: the id is longer than {@link MAX_WIKI_PAGE_ID_LENGTH} characters, or a name in it holds more than
|
|
10
|
+
* 200 bytes in UTF-8, the most a name built from data may hold (`MAX_PATH_NAME_BYTES` in `core/utils/pathName`).
|
|
11
|
+
* - `'character'`: the id holds a backslash, a colon, one of `"`, `*`, `<`, `>`, `?` and `|`, or a control
|
|
12
|
+
* character (U+0000 to U+001F, or U+007F), a NUL byte among them. On Windows a backslash separates folders, a
|
|
13
|
+
* colon names a drive or a file's stream, and the other six are refused in a name.
|
|
12
14
|
* - `'segment'`: a name between slashes is empty: the id starts or ends with `/`, or holds `//`.
|
|
13
15
|
* - `'dot'`: a name starts with a dot, `.` and `..` among them.
|
|
14
16
|
* - `'edge'`: a name starts or ends with a space, or ends with a dot. Windows drops those from a name, so the
|
|
@@ -33,10 +35,10 @@ export declare class InvalidWikiPageIdError extends Error {
|
|
|
33
35
|
* True when `id` has the wiki's id form: the page's path under `memory/` without `.md`, one or more names
|
|
34
36
|
* joined by `/` (`entities/johnny` is `memory/entities/johnny.md`). No name is empty or starts with a dot,
|
|
35
37
|
* so `.` and `..` are never names, and no name starts or ends with a space or ends with a dot, which
|
|
36
|
-
* Windows drops from a name; the id holds no backslash, no colon
|
|
37
|
-
* byte among them; it is at most {@link MAX_WIKI_PAGE_ID_LENGTH} characters
|
|
38
|
-
*
|
|
39
|
-
* `attachMemoryWiki` makes, has this form.
|
|
38
|
+
* Windows drops from a name; the id holds no backslash, no colon, none of `"`, `*`, `<`, `>`, `?` and `|`,
|
|
39
|
+
* and no control character, a NUL byte among them; it is at most {@link MAX_WIKI_PAGE_ID_LENGTH} characters,
|
|
40
|
+
* and each name in it at most 200 bytes in UTF-8; and it is not `index` in any case, the catalog's own id.
|
|
41
|
+
* Every id the store lists, and every id the default clusterer of `attachMemoryWiki` makes, has this form.
|
|
40
42
|
*/
|
|
41
43
|
export declare function isWikiPageId(id: unknown): id is string;
|
|
42
44
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WikiPageId.d.ts","sourceRoot":"","sources":["../../../../../src/cognition/substrate/memory/wiki/WikiPageId.ts"],"names":[],"mappings":"AAAA,uHAAuH;AACvH,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"WikiPageId.d.ts","sourceRoot":"","sources":["../../../../../src/cognition/substrate/memory/wiki/WikiPageId.ts"],"names":[],"mappings":"AAAA,uHAAuH;AACvH,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AASlC,mDAAmD;AACnD,eAAO,MAAM,uBAAuB,MAAM,CAAC;AAK3C;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,iBAAiB,GACzB,MAAM,GACN,OAAO,GACP,QAAQ,GACR,WAAW,GACX,SAAS,GACT,KAAK,GACL,MAAM,GACN,UAAU,GACV,SAAS,CAAC;AAiBd,4FAA4F;AAC5F,qBAAa,sBAAuB,SAAQ,KAAK;IAS7C,QAAQ,CAAC,OAAO,EAAE,iBAAiB;IARrC,oEAAoE;IACpE,QAAQ,CAAC,IAAI,0BAA0B;IAEvC;;;OAGG;gBAEQ,OAAO,EAAE,iBAAiB,EACnC,EAAE,EAAE,OAAO;CAKd;AAqBD;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,OAAO,GAAG,EAAE,IAAI,MAAM,CAEtD;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,OAAO,GAAG,OAAO,CAAC,EAAE,IAAI,MAAM,CAGlE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,MAAM,EACjB,EAAE,EAAE,OAAO,EACX,KAAK,GAAE,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,SAAS,GAAG,KAAK,CAAQ,GACvD,MAAM,CAKR"}
|
|
@@ -1,33 +1,23 @@
|
|
|
1
1
|
/** @fileoverview The id rule for wiki pages: an id names a file inside memory/, checked before any file is touched. */
|
|
2
2
|
import * as path from 'node:path';
|
|
3
|
+
import { MAX_PATH_NAME_BYTES, describeRefusedName, isRefusedPathCharacter, pathNameProblem, resolveInsideFolder, } from '../../../../core/utils/pathName.js';
|
|
3
4
|
/** The most characters a wiki page id may hold. */
|
|
4
5
|
export const MAX_WIKI_PAGE_ID_LENGTH = 512;
|
|
5
6
|
/** The id of the catalog file, `index.md`, which the store writes itself and never lists as a page. */
|
|
6
7
|
const CATALOG_ID = 'index';
|
|
7
|
-
/** The backslash's code: a folder separator on Windows. */
|
|
8
|
-
const BACKSLASH = 0x5c;
|
|
9
|
-
/** The colon's code: on Windows it names a drive (`C:page`) or a file's stream (`page:stream`). */
|
|
10
|
-
const COLON = 0x3a;
|
|
11
8
|
/** The part of the rule each problem breaks, as the error message words it. */
|
|
12
9
|
const RULE_BROKEN = {
|
|
13
10
|
type: 'a page id is a string',
|
|
14
11
|
empty: 'a page id is not empty',
|
|
15
|
-
length: `a page id is at most ${MAX_WIKI_PAGE_ID_LENGTH} characters
|
|
16
|
-
|
|
12
|
+
length: `a page id is at most ${MAX_WIKI_PAGE_ID_LENGTH} characters, ` +
|
|
13
|
+
`and each name in it at most ${MAX_PATH_NAME_BYTES} bytes in UTF-8`,
|
|
14
|
+
character: 'a page id holds no backslash, no colon, none of " * < > ? | and no control character',
|
|
17
15
|
segment: 'a page id is names joined by single slashes, with no slash at its start or end',
|
|
18
16
|
dot: 'no name in a page id starts with a dot',
|
|
19
17
|
edge: 'no name in a page id starts or ends with a space or ends with a dot',
|
|
20
18
|
reserved: 'the id index, in any case, names the catalog, index.md, which is not a page',
|
|
21
19
|
outside: "the page's file would be outside the memory folder",
|
|
22
20
|
};
|
|
23
|
-
/** The most characters of a refused id that its error message shows. */
|
|
24
|
-
const SHOWN_ID_CHARACTERS = 64;
|
|
25
|
-
/** The refused id as the message shows it: quoted and escaped, cut to its first characters. */
|
|
26
|
-
function describeId(id) {
|
|
27
|
-
if (typeof id !== 'string')
|
|
28
|
-
return `of type ${id === null ? 'null' : typeof id}`;
|
|
29
|
-
return JSON.stringify(id.length > SHOWN_ID_CHARACTERS ? `${id.slice(0, SHOWN_ID_CHARACTERS)}...` : id);
|
|
30
|
-
}
|
|
31
21
|
/** Thrown when a wiki page id is refused. Nothing is read or written for the refused id. */
|
|
32
22
|
export class InvalidWikiPageIdError extends Error {
|
|
33
23
|
/**
|
|
@@ -35,14 +25,17 @@ export class InvalidWikiPageIdError extends Error {
|
|
|
35
25
|
* @param id - The refused id. The message shows at most its first 64 characters, escaped.
|
|
36
26
|
*/
|
|
37
27
|
constructor(problem, id) {
|
|
38
|
-
super(`wiki page id ${
|
|
28
|
+
super(`wiki page id ${describeRefusedName(id)} refused: ${RULE_BROKEN[problem]}`);
|
|
39
29
|
this.problem = problem;
|
|
40
30
|
/** A stable code for callers that branch on the kind of failure. */
|
|
41
31
|
this.code = 'INVALID_WIKI_PAGE_ID';
|
|
42
32
|
this.name = 'InvalidWikiPageIdError';
|
|
43
33
|
}
|
|
44
34
|
}
|
|
45
|
-
/**
|
|
35
|
+
/**
|
|
36
|
+
* The part of the id rule `id` breaks, or null when the rule accepts it. Each name between slashes is held to the
|
|
37
|
+
* rule every name built from data is held to (`pathNameProblem`), after the whole id is checked.
|
|
38
|
+
*/
|
|
46
39
|
function problemOf(id) {
|
|
47
40
|
if (typeof id !== 'string')
|
|
48
41
|
return 'type';
|
|
@@ -51,17 +44,14 @@ function problemOf(id) {
|
|
|
51
44
|
if (id.length > MAX_WIKI_PAGE_ID_LENGTH)
|
|
52
45
|
return 'length';
|
|
53
46
|
for (let i = 0; i < id.length; i++) {
|
|
54
|
-
|
|
55
|
-
if (code <= 0x1f || code === 0x7f || code === BACKSLASH || code === COLON)
|
|
47
|
+
if (isRefusedPathCharacter(id.charCodeAt(i)))
|
|
56
48
|
return 'character';
|
|
57
49
|
}
|
|
58
50
|
for (const name of id.split('/')) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
if (
|
|
62
|
-
return '
|
|
63
|
-
if (name.startsWith(' ') || name.endsWith(' ') || name.endsWith('.'))
|
|
64
|
-
return 'edge';
|
|
51
|
+
const problem = pathNameProblem(name);
|
|
52
|
+
// An empty name sits between two slashes, or at the id's start or end.
|
|
53
|
+
if (problem)
|
|
54
|
+
return problem === 'empty' ? 'segment' : problem;
|
|
65
55
|
}
|
|
66
56
|
return id.toLowerCase() === CATALOG_ID ? 'reserved' : null;
|
|
67
57
|
}
|
|
@@ -69,10 +59,10 @@ function problemOf(id) {
|
|
|
69
59
|
* True when `id` has the wiki's id form: the page's path under `memory/` without `.md`, one or more names
|
|
70
60
|
* joined by `/` (`entities/johnny` is `memory/entities/johnny.md`). No name is empty or starts with a dot,
|
|
71
61
|
* so `.` and `..` are never names, and no name starts or ends with a space or ends with a dot, which
|
|
72
|
-
* Windows drops from a name; the id holds no backslash, no colon
|
|
73
|
-
* byte among them; it is at most {@link MAX_WIKI_PAGE_ID_LENGTH} characters
|
|
74
|
-
*
|
|
75
|
-
* `attachMemoryWiki` makes, has this form.
|
|
62
|
+
* Windows drops from a name; the id holds no backslash, no colon, none of `"`, `*`, `<`, `>`, `?` and `|`,
|
|
63
|
+
* and no control character, a NUL byte among them; it is at most {@link MAX_WIKI_PAGE_ID_LENGTH} characters,
|
|
64
|
+
* and each name in it at most 200 bytes in UTF-8; and it is not `index` in any case, the catalog's own id.
|
|
65
|
+
* Every id the store lists, and every id the default clusterer of `attachMemoryWiki` makes, has this form.
|
|
76
66
|
*/
|
|
77
67
|
export function isWikiPageId(id) {
|
|
78
68
|
return problemOf(id) === null;
|
|
@@ -101,10 +91,8 @@ export function assertWikiPageId(id) {
|
|
|
101
91
|
*/
|
|
102
92
|
export function resolveWikiPagePath(memoryDir, id, paths = path) {
|
|
103
93
|
assertWikiPageId(id);
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
const inside = root.endsWith(paths.sep) ? root : root + paths.sep;
|
|
107
|
-
if (!file.startsWith(inside))
|
|
94
|
+
const file = resolveInsideFolder(memoryDir, [`${id}.md`], paths);
|
|
95
|
+
if (file === null)
|
|
108
96
|
throw new InvalidWikiPageIdError('outside', id);
|
|
109
97
|
return file;
|
|
110
98
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WikiPageId.js","sourceRoot":"","sources":["../../../../../src/cognition/substrate/memory/wiki/WikiPageId.ts"],"names":[],"mappings":"AAAA,uHAAuH;AACvH,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"WikiPageId.js","sourceRoot":"","sources":["../../../../../src/cognition/substrate/memory/wiki/WikiPageId.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Writing below a folder whose contents another process may change: folders are made one name at a
|
|
3
|
+
* time and never through a link, and a file is opened for writing never through a link, never waiting, and only
|
|
4
|
+
* when it is a regular file with one name.
|
|
5
|
+
*
|
|
6
|
+
* The Markdown and Obsidian memory exporters write a file per trace below an export folder, and the skill exporter
|
|
7
|
+
* writes a tool's files below a skills folder. Whoever can write below such a folder could put there a link that
|
|
8
|
+
* leads elsewhere, a second name for a file elsewhere, or a named pipe that holds a writer up, so both write
|
|
9
|
+
* through the functions here. The folder itself is the caller's and may be a link. The checks run as each folder
|
|
10
|
+
* is made and each file opened; Node has no `openat`, so a process that swaps a folder for a link between a check
|
|
11
|
+
* and the write is outside what they stop.
|
|
12
|
+
*
|
|
13
|
+
* @module agentos/core/utils/linkFreeWrite
|
|
14
|
+
*/
|
|
15
|
+
import { type FileHandle } from 'node:fs/promises';
|
|
16
|
+
/**
|
|
17
|
+
* Why a file was not opened: `link` when a symbolic link holds its place or the file has a second name (a hard
|
|
18
|
+
* link), and `special` when something other than a regular file holds its place (a folder, a named pipe, a socket,
|
|
19
|
+
* a device).
|
|
20
|
+
*/
|
|
21
|
+
export type OpenRefusal = 'link' | 'special';
|
|
22
|
+
/** A file open for writing and checked, and the identity of the file the open reached. */
|
|
23
|
+
export interface OpenedFile {
|
|
24
|
+
/** The open file. Nothing has been emptied or written. */
|
|
25
|
+
handle: FileHandle;
|
|
26
|
+
/**
|
|
27
|
+
* The file's device and inode numbers, or null when the file system reports an inode of 0, which names no file.
|
|
28
|
+
* Two names that open one file give the same identity.
|
|
29
|
+
*/
|
|
30
|
+
identity: string | null;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Make the folders `relative` names under `root`, one name at a time, and stop at a link. A folder this makes is
|
|
34
|
+
* never a link, so a file written into it stays under `root`.
|
|
35
|
+
*
|
|
36
|
+
* @param root - The folder the others are made in. It may itself be a link.
|
|
37
|
+
* @param relative - The folders' path under `root`.
|
|
38
|
+
* @returns True when every folder is in place and none of them is a link.
|
|
39
|
+
*/
|
|
40
|
+
export declare function makeFoldersOutsideLinks(root: string, relative: string): Promise<boolean>;
|
|
41
|
+
/**
|
|
42
|
+
* Look at a file's place without opening it. A caller that writes several files, all of them or none, looks at
|
|
43
|
+
* every place before it opens any file, so a refusal makes no file. The look does not see a change made after it;
|
|
44
|
+
* {@link openFileOutsideLinks} checks again.
|
|
45
|
+
*
|
|
46
|
+
* @param file - Absolute path of the file.
|
|
47
|
+
* @returns `link` when a symbolic link holds the place or the file there has a second name, `special` when
|
|
48
|
+
* something other than a regular file holds it, or null when the place is free or holds a regular file with one
|
|
49
|
+
* name.
|
|
50
|
+
* @throws Any error the look meets other than a missing file.
|
|
51
|
+
*/
|
|
52
|
+
export declare function lookOutsideLinks(file: string): Promise<OpenRefusal | null>;
|
|
53
|
+
/**
|
|
54
|
+
* Open a file for writing, in a folder already made, and check what the open reached. A symbolic link in the
|
|
55
|
+
* file's place is refused before the open, and where the platform has `O_NOFOLLOW` the open refuses one put there
|
|
56
|
+
* since. A folder fails the open, and where the platform has `O_NONBLOCK` so does a named pipe that no process
|
|
57
|
+
* reads, at once. An open file that is not a regular file (a named pipe that a process reads, a device) is refused,
|
|
58
|
+
* and so is a file with a second name (a hard link), which is the same file as that name and may lie outside the
|
|
59
|
+
* folder. Nothing is emptied or written here; a refused file is closed.
|
|
60
|
+
*
|
|
61
|
+
* @param file - Absolute path of the file.
|
|
62
|
+
* @returns The open file and its identity, or the refusal.
|
|
63
|
+
* @throws Any other error the look or the open meets.
|
|
64
|
+
*/
|
|
65
|
+
export declare function openFileOutsideLinks(file: string): Promise<OpenedFile | OpenRefusal>;
|
|
66
|
+
//# sourceMappingURL=linkFreeWrite.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"linkFreeWrite.d.ts","sourceRoot":"","sources":["../../../src/core/utils/linkFreeWrite.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAW,EAAE,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AA2BvD;;;;GAIG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,SAAS,CAAC;AAE7C,0FAA0F;AAC1F,MAAM,WAAW,UAAU;IACzB,0DAA0D;IAC1D,MAAM,EAAE,UAAU,CAAC;IACnB;;;OAGG;IACH,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED;;;;;;;GAOG;AACH,wBAAsB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAkB9F;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAMhF;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,WAAW,CAAC,CAmB1F"}
|