feat(linkedin-studio): second-brain SB-S0 foundation — brain/ scaffold + profile fold + id/provenance spine [skip-docs]
SB-S0 (Foundation) of the second-brain arc: a new TS package scripts/brain/
(structural copy of specifics-bank) establishing the spine later slices hang on.
TDD throughout (failing test first); fold scope = P1+P2 only per operator decision.
- types.ts: one provenance vocab (human|published|ai-draft) + the six-field
ProfileFact record + two-layer ProfileDoc.
- id.ts: slugify + mintEntityId (sha256[:12], kind-namespaced, slug-keyed so the
id is stable across value edits) + normalizeProvenance (throws on unknown). [SC4]
- profile.ts: no-YAML line-grammar parse/serialize (parse∘serialize = identity over
the whole doc; values may contain ]/|/quotes) [SC2] + foldUserProfile: lossless,
idempotent, source-absent-aware fold of config/user-profile.template.md. Pinned
extraction — P1 labeled scalars (group-headers skipped, [placeholder]→empty) + P2
expertise group; stops at "### Research Tooling" so deferred explainer prose can't
leak in as fields. Checkbox-prefs (Goals/Tone/MCPs/Assets) deferred (§8). [SC3]
- dataRoot.ts: inline per-package resolver (repo idiom; no new seam → SC6).
- scaffold.ts/cli.ts: idempotent `brain init` — brain/{index,profile,operations}.md
+ journal/ + ingest/{inbox,published} under the data-dir; compare-then-skip, never
clobbers a user edit. No session-start wiring (SB-S2 owns it). [SC1]
Gate: new BRAIN floor in test-runner.sh (34 tests; trends/specifics/contract floors
unchanged) + anti-erosion floor 74→75. Full gate 90/0/0, tsc --noEmit clean. [SC5/SC6]
No new command/agent/reference → no version bump, no structure-count change.
Refs docs/second-brain/{brief,plan-sb-s0,architecture}.md.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RigJBiRFNtFZKCz21qNbQ4
This commit is contained in:
parent
d6acb5d36c
commit
8c927198f5
17 changed files with 1554 additions and 8 deletions
45
scripts/brain/src/cli.ts
Normal file
45
scripts/brain/src/cli.ts
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#!/usr/bin/env node
|
||||
/**
|
||||
* CLI for the second-brain foundation (SB-S0).
|
||||
*
|
||||
* node --import tsx src/cli.ts init
|
||||
*
|
||||
* `init` scaffolds the `brain/` + `ingest/` tree under the per-user data dir
|
||||
* (`LINKEDIN_STUDIO_DATA` overrides the root). Idempotent — running it twice is a
|
||||
* no-op. No session-start wiring yet (SB-S2 owns that); this is the invokable
|
||||
* subcommand only.
|
||||
*
|
||||
* Exit code: 0 on success, 2 on usage error.
|
||||
*/
|
||||
|
||||
import { dataRoot } from "./dataRoot.js";
|
||||
import { initBrain } from "./scaffold.js";
|
||||
|
||||
function usage(msg: string): never {
|
||||
console.error(`error: ${msg}`);
|
||||
console.error("usage:\n init");
|
||||
process.exit(2);
|
||||
}
|
||||
|
||||
function main(): void {
|
||||
const [command] = process.argv.slice(2);
|
||||
|
||||
if (command === "init") {
|
||||
const { created, skipped } = initBrain();
|
||||
console.log(`Brain root: ${dataRoot("brain")}`);
|
||||
if (created.length > 0) {
|
||||
console.log(`Created (${created.length}):`);
|
||||
for (const c of created) console.log(` + ${c}`);
|
||||
}
|
||||
if (skipped.length > 0) {
|
||||
console.log(`Skipped — already present (${skipped.length}):`);
|
||||
for (const s of skipped) console.log(` · ${s}`);
|
||||
}
|
||||
if (created.length === 0) console.log("Already initialised — nothing to do.");
|
||||
return;
|
||||
}
|
||||
|
||||
usage(command ? `unknown command: ${command}` : "no command given");
|
||||
}
|
||||
|
||||
main();
|
||||
Loading…
Add table
Add a link
Reference in a new issue