ultimate-brain 0.0.0-stage → 0.1.1
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/.agents/skills/README.md +3 -0
- package/.agents/skills/brain-apply/SKILL.md +80 -0
- package/.agents/skills/brain-connect-notion/SKILL.md +55 -0
- package/.agents/skills/brain-ingest/SKILL.md +104 -0
- package/.agents/skills/brain-ingest/references/cli-inputs.md +106 -0
- package/.agents/skills/brain-ingest/references/example-batch.json +165 -0
- package/.agents/skills/brain-ingest/references/extraction.md +103 -0
- package/.agents/skills/brain-ingest/references/notion.md +61 -0
- package/.agents/skills/brain-notion-change/SKILL.md +57 -0
- package/.agents/skills/brain-query/SKILL.md +62 -0
- package/.agents/skills/brain-sync/SKILL.md +64 -0
- package/.agents/skills/brain-sync/references/formats.md +53 -0
- package/LICENSE +21 -0
- package/README.md +40 -2
- package/bin/brain.js +5 -0
- package/dist/cli.js +83 -0
- package/dist/commands/apply.js +34 -0
- package/dist/commands/config.js +96 -0
- package/dist/commands/id.js +32 -0
- package/dist/commands/index.js +58 -0
- package/dist/commands/init.js +233 -0
- package/dist/commands/link.js +285 -0
- package/dist/commands/lint.js +47 -0
- package/dist/commands/log.js +48 -0
- package/dist/commands/note.js +36 -0
- package/dist/commands/proposal.js +57 -0
- package/dist/commands/query.js +38 -0
- package/dist/commands/status.js +98 -0
- package/dist/commands/sync.js +53 -0
- package/dist/commands/upgrade.js +143 -0
- package/dist/commands/views.js +111 -0
- package/dist/lib/apply.js +524 -0
- package/dist/lib/args.js +63 -0
- package/dist/lib/brain-path.js +91 -0
- package/dist/lib/brain.js +36 -0
- package/dist/lib/command.js +61 -0
- package/dist/lib/errors.js +33 -0
- package/dist/lib/frontmatter.js +171 -0
- package/dist/lib/fs-safe.js +140 -0
- package/dist/lib/ids.js +51 -0
- package/dist/lib/index-builder.js +216 -0
- package/dist/lib/input.js +45 -0
- package/dist/lib/lint.js +336 -0
- package/dist/lib/log.js +44 -0
- package/dist/lib/note-new.js +119 -0
- package/dist/lib/notes.js +95 -0
- package/dist/lib/paths.js +49 -0
- package/dist/lib/proposals.js +229 -0
- package/dist/lib/query.js +163 -0
- package/dist/lib/schemas.js +51 -0
- package/dist/lib/skills.js +60 -0
- package/dist/lib/sync.js +714 -0
- package/dist/lib/time.js +21 -0
- package/dist/lib/views.js +139 -0
- package/dist/lib/warnings.js +9 -0
- package/dist/lib/workspace.js +183 -0
- package/package.json +45 -4
- package/spec/schemas/brain.schema.json +200 -0
- package/spec/schemas/note.schema.json +1059 -0
- package/spec/schemas/proposal.schema.json +559 -0
- package/templates/README.md +44 -0
- package/templates/brain/AGENTS.md +54 -0
- package/templates/brain/CLAUDE.md +1 -0
- package/templates/brain/_proposals/.gitkeep +0 -0
- package/templates/brain/archive/goals/.gitkeep +0 -0
- package/templates/brain/archive/projects/.gitkeep +0 -0
- package/templates/brain/areas/.gitkeep +0 -0
- package/templates/brain/brain.json +35 -0
- package/templates/brain/gitignore +6 -0
- package/templates/brain/goals/.gitkeep +0 -0
- package/templates/brain/index.md +3 -0
- package/templates/brain/knowledge/concepts/.gitkeep +0 -0
- package/templates/brain/knowledge/decisions/.gitkeep +0 -0
- package/templates/brain/knowledge/meetings/.gitkeep +0 -0
- package/templates/brain/knowledge/orgs/.gitkeep +0 -0
- package/templates/brain/knowledge/people/.gitkeep +0 -0
- package/templates/brain/knowledge/questions/.gitkeep +0 -0
- package/templates/brain/memories/.gitkeep +0 -0
- package/templates/brain/projects/.gitkeep +0 -0
- package/templates/brain/sources/notion/.gitkeep +0 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { Ajv2020 } from "ajv/dist/2020.js";
|
|
3
|
+
/** The JSON Schemas of spec/schemas/, the single source of truth for file shapes. */
|
|
4
|
+
const SCHEMA_DIR = new URL("../../spec/schemas/", import.meta.url);
|
|
5
|
+
const KNOWLEDGE_TYPES = new Set([
|
|
6
|
+
"area", "goal", "project", "person", "org", "meeting", "decision", "question", "concept", "memory",
|
|
7
|
+
]);
|
|
8
|
+
let cached;
|
|
9
|
+
export function loadSchemas() {
|
|
10
|
+
if (cached !== undefined)
|
|
11
|
+
return cached;
|
|
12
|
+
const read = (name) => JSON.parse(readFileSync(new URL(name, SCHEMA_DIR), "utf8"));
|
|
13
|
+
const note = read("note.schema.json");
|
|
14
|
+
const proposal = read("proposal.schema.json");
|
|
15
|
+
const brain = read("brain.schema.json");
|
|
16
|
+
const ajv = new Ajv2020({ allErrors: true, strict: false });
|
|
17
|
+
ajv.addSchema(note);
|
|
18
|
+
ajv.addSchema(proposal);
|
|
19
|
+
ajv.addSchema(brain);
|
|
20
|
+
const keys = (schema) => Object.keys(schema?.properties ?? {});
|
|
21
|
+
const known = new Map();
|
|
22
|
+
for (const type of [...KNOWLEDGE_TYPES, "source", "view"]) {
|
|
23
|
+
const set = new Set([...keys(note), ...keys(note.$defs?.[type])]);
|
|
24
|
+
if (KNOWLEDGE_TYPES.has(type))
|
|
25
|
+
for (const key of keys(note.$defs?.knowledge))
|
|
26
|
+
set.add(key);
|
|
27
|
+
known.set(type, set);
|
|
28
|
+
}
|
|
29
|
+
known.set("proposal", new Set(keys(proposal)));
|
|
30
|
+
cached = {
|
|
31
|
+
note: ajv.getSchema(note.$id),
|
|
32
|
+
proposal: ajv.getSchema(proposal.$id),
|
|
33
|
+
brain: ajv.getSchema(brain.$id),
|
|
34
|
+
knownKeys: (type) => known.get(type),
|
|
35
|
+
};
|
|
36
|
+
return cached;
|
|
37
|
+
}
|
|
38
|
+
/** Readable messages for the errors that matter (composition keywords are noise). */
|
|
39
|
+
export function describeErrors(errors) {
|
|
40
|
+
const messages = (errors ?? [])
|
|
41
|
+
.filter((error) => !["if", "anyOf", "allOf", "oneOf"].includes(error.keyword))
|
|
42
|
+
.map((error) => {
|
|
43
|
+
const where = error.instancePath === "" ? "frontmatter" : error.instancePath.slice(1).replaceAll("/", ".");
|
|
44
|
+
if (error.keyword === "required")
|
|
45
|
+
return `${where}: missing ${String(error.params.missingProperty)}`;
|
|
46
|
+
if (error.keyword === "not")
|
|
47
|
+
return `${where}: has a field this type must not have`;
|
|
48
|
+
return `${where}: ${error.message ?? error.keyword}`;
|
|
49
|
+
});
|
|
50
|
+
return [...new Set(messages)];
|
|
51
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { lstat, readdir, readFile, realpath } from "node:fs/promises";
|
|
2
|
+
import { join, relative, sep } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { BrainError } from "./errors.js";
|
|
5
|
+
const SKILLS_ROOT = fileURLToPath(new URL("../../.agents/skills/", import.meta.url));
|
|
6
|
+
/** Skills the package ships for Codex (decision 0029), optionally limited to one skill name. */
|
|
7
|
+
export async function listShippedSkillFiles(only) {
|
|
8
|
+
let root;
|
|
9
|
+
try {
|
|
10
|
+
root = await realpath(SKILLS_ROOT);
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
throw new BrainError("INTERNAL", "This package does not include .agents/skills/");
|
|
14
|
+
}
|
|
15
|
+
const files = [];
|
|
16
|
+
async function visit(folder) {
|
|
17
|
+
for (const entry of await readdir(folder, { withFileTypes: true })) {
|
|
18
|
+
const source = join(folder, entry.name);
|
|
19
|
+
if (entry.isSymbolicLink())
|
|
20
|
+
throw new BrainError("OUTSIDE_ROOT", `Skills contain a symbolic link: ${source}`);
|
|
21
|
+
if (entry.isDirectory())
|
|
22
|
+
await visit(source);
|
|
23
|
+
else if (entry.isFile()) {
|
|
24
|
+
files.push({ relative: relative(root, source).split(sep).join("/"), content: await readFile(source) });
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
await visit(root);
|
|
29
|
+
const selected = files.filter((file) => file.relative.includes("/") && (only === undefined || file.relative.startsWith(`${only}/`)));
|
|
30
|
+
if (only !== undefined && selected.length === 0)
|
|
31
|
+
throw new BrainError("INTERNAL", `Skill ${only} is not shipped with this package`);
|
|
32
|
+
return selected.sort((a, b) => (a.relative < b.relative ? -1 : a.relative > b.relative ? 1 : 0));
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Refuses (OUTSIDE_ROOT) a product-owned path under `root` whose existing parts are a symbolic link, a non-folder
|
|
36
|
+
* where a folder is needed, or a non-file at the end, so a write or removal can't follow a link out of the repo.
|
|
37
|
+
* Call it while planning, before anything is written.
|
|
38
|
+
*/
|
|
39
|
+
export async function assertPlainPath(root, path, last = "file") {
|
|
40
|
+
const parts = path.split("/");
|
|
41
|
+
for (let index = 1; index <= parts.length; index += 1) {
|
|
42
|
+
const current = parts.slice(0, index).join("/");
|
|
43
|
+
let metadata;
|
|
44
|
+
try {
|
|
45
|
+
metadata = await lstat(join(root, current));
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT")
|
|
49
|
+
return;
|
|
50
|
+
throw error;
|
|
51
|
+
}
|
|
52
|
+
if (metadata.isSymbolicLink())
|
|
53
|
+
throw new BrainError("OUTSIDE_ROOT", `Refusing to write through a symbolic link: ${current}`);
|
|
54
|
+
const wantFolder = index < parts.length || last === "folder";
|
|
55
|
+
if (wantFolder && !metadata.isDirectory())
|
|
56
|
+
throw new BrainError("OUTSIDE_ROOT", `Expected a folder: ${current}`);
|
|
57
|
+
if (!wantFolder && !metadata.isFile())
|
|
58
|
+
throw new BrainError("OUTSIDE_ROOT", `Expected a file: ${current}`);
|
|
59
|
+
}
|
|
60
|
+
}
|