@forwardimpact/outpost 3.12.0 → 3.13.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 +2 -2
- package/bin/fit-outpost.js +3 -2
- package/package.json +6 -5
- package/src/agent-path.js +10 -6
- package/src/agent-runner.js +28 -24
- package/src/index.js +2 -3
- package/src/kb-manager.js +75 -20
- package/src/kb-validator.js +762 -0
- package/src/outpost.js +108 -39
- package/src/posture.js +3 -3
- package/src/privilege.js +11 -11
- package/src/scheduler.js +14 -12
- package/src/socket-server.js +19 -18
- package/src/spawn-env.js +7 -6
- package/src/state-manager.js +2 -2
- package/templates/.claude/agents/chief-of-staff.md +32 -24
- package/templates/.claude/agents/concierge.md +26 -17
- package/templates/.claude/agents/head-hunter.md +34 -26
- package/templates/.claude/agents/librarian.md +26 -18
- package/templates/.claude/agents/postman.md +26 -18
- package/templates/.claude/agents/recruiter.md +38 -27
- package/templates/.claude/skills/anarlog-follow/SKILL.md +91 -66
- package/templates/.claude/skills/anarlog-follow/references/coaching.md +22 -21
- package/templates/.claude/skills/anarlog-follow/references/sessions.md +52 -0
- package/templates/.claude/skills/anarlog-process/SKILL.md +108 -62
- package/templates/.claude/skills/anarlog-process/references/extraction.md +41 -29
- package/templates/.claude/skills/anarlog-process/references/sessions.md +92 -58
- package/templates/.claude/skills/anarlog-process/scripts/scan.mjs +402 -160
- package/templates/.claude/skills/candidate-report/SKILL.md +41 -36
- package/templates/.claude/skills/candidate-report/references/report-template.html +10 -10
- package/templates/.claude/skills/candidate-report/references/report.css +4 -4
- package/templates/.claude/skills/candidate-report/references/rubric.md +15 -14
- package/templates/.claude/skills/candidate-report/scripts/render-pdf.mjs +2 -2
- package/templates/.claude/skills/changelog/SKILL.md +122 -67
- package/templates/.claude/skills/deck-create/SKILL.md +90 -32
- package/templates/.claude/skills/deck-create/references/slide.css +4 -4
- package/templates/.claude/skills/deck-create/scripts/convert-to-pdf.mjs +6 -6
- package/templates/.claude/skills/deck-review/SKILL.md +63 -58
- package/templates/.claude/skills/deck-review/assets/slide-annotator.js +58 -49
- package/templates/.claude/skills/deck-summarize/SKILL.md +55 -45
- package/templates/.claude/skills/deck-summarize/references/brief-template.md +5 -4
- package/templates/.claude/skills/deck-summarize/scripts/extract-pptx.mjs +8 -7
- package/templates/.claude/skills/doc-collab/SKILL.md +39 -34
- package/templates/.claude/skills/doc-create/SKILL.md +27 -23
- package/templates/.claude/skills/doc-create/scripts/convert-to-pdf.mjs +6 -6
- package/templates/.claude/skills/draft-emails/SKILL.md +63 -53
- package/templates/.claude/skills/draft-emails/references/template.md +2 -2
- package/templates/.claude/skills/draft-emails/scripts/scan-emails.mjs +15 -8
- package/templates/.claude/skills/draft-emails/scripts/send-email.mjs +19 -11
- package/templates/.claude/skills/extract-entities/SKILL.md +76 -75
- package/templates/.claude/skills/extract-entities/references/TEMPLATES.md +6 -5
- package/templates/.claude/skills/extract-entities/references/conditions.md +20 -18
- package/templates/.claude/skills/extract-entities/references/content.md +10 -9
- package/templates/.claude/skills/extract-entities/references/links.md +37 -13
- package/templates/.claude/skills/extract-entities/references/recruitment.md +30 -24
- package/templates/.claude/skills/extract-entities/references/resolution.md +14 -14
- package/templates/.claude/skills/extract-entities/references/sources.md +9 -9
- package/templates/.claude/skills/extract-entities/references/templates-conditions.md +12 -6
- package/templates/.claude/skills/extract-entities/references/templates-people-orgs.md +29 -10
- package/templates/.claude/skills/extract-entities/references/templates-priorities.md +10 -4
- package/templates/.claude/skills/extract-entities/references/templates-projects-topics.md +19 -7
- package/templates/.claude/skills/extract-entities/scripts/state.mjs +9 -8
- package/templates/.claude/skills/meeting-prep/SKILL.md +42 -36
- package/templates/.claude/skills/organize-files/SKILL.md +27 -22
- package/templates/.claude/skills/organize-files/scripts/organize-by-type.mjs +5 -4
- package/templates/.claude/skills/organize-files/scripts/summarize.mjs +4 -4
- package/templates/.claude/skills/person-identify/SKILL.md +77 -27
- package/templates/.claude/skills/person-identify/scripts/identify.sh +125 -26
- package/templates/.claude/skills/person-lookup/SKILL.md +34 -30
- package/templates/.claude/skills/person-lookup/scripts/lookup.sh +46 -17
- package/templates/.claude/skills/req-assess/SKILL.md +44 -36
- package/templates/.claude/skills/req-assess/references/interview-template.md +7 -2
- package/templates/.claude/skills/req-assess/references/panel-template.md +7 -2
- package/templates/.claude/skills/req-assess/references/rubric.md +13 -13
- package/templates/.claude/skills/req-bundle/SKILL.md +164 -0
- package/templates/.claude/skills/req-bundle/references/matching.md +70 -0
- package/templates/.claude/skills/req-bundle/references/pdf-structure.md +74 -0
- package/templates/.claude/skills/req-bundle/scripts/split-bundle.mjs +377 -0
- package/templates/.claude/skills/req-decide/SKILL.md +52 -41
- package/templates/.claude/skills/req-decide/references/rubric.md +11 -10
- package/templates/.claude/skills/req-decide/references/template.md +2 -2
- package/templates/.claude/skills/req-forget/SKILL.md +58 -39
- package/templates/.claude/skills/req-forget/references/classify.md +15 -13
- package/templates/.claude/skills/req-forget/references/locations.md +27 -22
- package/templates/.claude/skills/req-forget/references/report-template.md +24 -16
- package/templates/.claude/skills/req-scan/SKILL.md +27 -25
- package/templates/.claude/skills/req-scan/references/fallbacks.md +9 -9
- package/templates/.claude/skills/req-scan/references/filters.md +13 -13
- package/templates/.claude/skills/req-scan/references/sources.md +7 -7
- package/templates/.claude/skills/req-scan/references/state.md +1 -1
- package/templates/.claude/skills/req-scan/references/template.md +11 -1
- package/templates/.claude/skills/req-scan/scripts/state.mjs +3 -2
- package/templates/.claude/skills/req-screen/SKILL.md +96 -50
- package/templates/.claude/skills/req-screen/references/rubric.md +46 -50
- package/templates/.claude/skills/req-screen/references/scoring.md +79 -0
- package/templates/.claude/skills/req-screen/references/template.md +29 -17
- package/templates/.claude/skills/req-track/SKILL.md +76 -76
- package/templates/.claude/skills/req-track/references/fields.md +31 -27
- package/templates/.claude/skills/req-track/references/overlays.md +42 -0
- package/templates/.claude/skills/req-track/references/signals.md +12 -12
- package/templates/.claude/skills/req-track/references/statuses.md +3 -2
- package/templates/.claude/skills/req-track/references/templates.md +28 -27
- package/templates/.claude/skills/req-workday/SKILL.md +69 -40
- package/templates/.claude/skills/req-workday/references/brief.md +81 -0
- package/templates/.claude/skills/req-workday/references/status-mapping.md +5 -5
- package/templates/.claude/skills/req-workday/references/templates.md +11 -78
- package/templates/.claude/skills/req-workday/references/xlsx-format.md +26 -7
- package/templates/.claude/skills/req-workday/scripts/parse-workday.mjs +113 -35
- package/templates/.claude/skills/send-chat/SKILL.md +58 -54
- package/templates/.claude/skills/sync-apple-calendar/SKILL.md +23 -19
- package/templates/.claude/skills/sync-apple-calendar/references/SCHEMA.md +7 -7
- package/templates/.claude/skills/sync-apple-calendar/scripts/query.mjs +6 -6
- package/templates/.claude/skills/sync-apple-calendar/scripts/sync.mjs +9 -8
- package/templates/.claude/skills/sync-apple-mail/SKILL.md +20 -14
- package/templates/.claude/skills/sync-apple-mail/references/SCHEMA.md +10 -10
- package/templates/.claude/skills/sync-apple-mail/scripts/parse-emlx.mjs +9 -9
- package/templates/.claude/skills/sync-apple-mail/scripts/sync-helpers.mjs +16 -13
- package/templates/.claude/skills/sync-apple-mail/scripts/sync.mjs +3 -3
- package/templates/.claude/skills/sync-teams/SKILL.md +46 -43
- package/templates/.claude/skills/sync-teams/scripts/idb-reader.mjs +22 -21
- package/templates/.claude/skills/sync-teams/scripts/leveldb-reader.mjs +4 -4
- package/templates/.claude/skills/sync-teams/scripts/sync.mjs +4 -4
- package/templates/.claude/skills/upstream-instructions/SKILL.md +43 -41
- package/templates/.claude/skills/upstream-instructions/references/examples.md +5 -5
- package/templates/CLAUDE.md +97 -85
- package/templates/MIGRATION.md +359 -0
- package/templates/registry.yaml +25 -0
- package/templates/.claude/skills/anarlog-follow/scripts/follow.mjs +0 -243
- package/templates/.claude/skills/anarlog-trim/SKILL.md +0 -183
package/README.md
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
<!-- BEGIN:description — Do not edit. Generated from package.json. -->
|
|
4
4
|
|
|
5
|
-
Personal operations center — context from email, calendar, and
|
|
6
|
-
|
|
5
|
+
Personal operations center — context assembled from email, calendar, and
|
|
6
|
+
knowledge so preparation is continuous instead of a morning scramble.
|
|
7
7
|
|
|
8
8
|
<!-- END:description -->
|
|
9
9
|
|
package/bin/fit-outpost.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
//
|
|
3
|
-
// bag
|
|
2
|
+
// This file is the thin entry point. It is the sole construction site for the
|
|
3
|
+
// runtime collaborator bag. It threads that bag into the dispatch in
|
|
4
|
+
// src/outpost.js through run(runtime, version).
|
|
4
5
|
import "@forwardimpact/libpreflight/node22";
|
|
5
6
|
|
|
6
7
|
import { resolveVersion } from "@forwardimpact/libcli";
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forwardimpact/outpost",
|
|
3
|
-
"version": "3.
|
|
4
|
-
"description": "Personal operations center — context from email, calendar, and knowledge
|
|
3
|
+
"version": "3.13.0",
|
|
4
|
+
"description": "Personal operations center — context assembled from email, calendar, and knowledge so preparation is continuous instead of a morning scramble.",
|
|
5
5
|
"homepage": "https://www.forwardimpact.team",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -14,12 +14,12 @@
|
|
|
14
14
|
{
|
|
15
15
|
"user": "Empowered Engineers",
|
|
16
16
|
"goal": "Be Prepared and Productive",
|
|
17
|
-
"trigger": "
|
|
17
|
+
"trigger": "The engineer walks into a meeting cold because context is scattered across email, Slack, and last week's notes.",
|
|
18
18
|
"bigHire": "keep track of people, projects, and threads without depending on memory.",
|
|
19
19
|
"littleHire": "walk into every meeting already oriented.",
|
|
20
20
|
"competesWith": "morning email scan; re-reading calendar invites; personal notes; asking colleagues for context",
|
|
21
21
|
"forces": {
|
|
22
|
-
"push": "Context-switching compounds
|
|
22
|
+
"push": "Context-switching compounds. Starting cold wastes everyone's time.",
|
|
23
23
|
"pull": "Continuous awareness without continuous effort — context assembled.",
|
|
24
24
|
"habit": "Morning routines and tracking systems that feel 'good enough.'",
|
|
25
25
|
"anxiety": "Delegating awareness to a system feels like losing control."
|
|
@@ -51,7 +51,8 @@
|
|
|
51
51
|
"@forwardimpact/libcli": "^0.1.0",
|
|
52
52
|
"@forwardimpact/libpreflight": "^0.1.0",
|
|
53
53
|
"@forwardimpact/libtelemetry": "^0.1.33",
|
|
54
|
-
"@forwardimpact/libutil": "^0.1.0"
|
|
54
|
+
"@forwardimpact/libutil": "^0.1.0",
|
|
55
|
+
"yaml": "^2.9.0"
|
|
55
56
|
},
|
|
56
57
|
"devDependencies": {
|
|
57
58
|
"@forwardimpact/libmock": "^0.1.0"
|
package/src/agent-path.js
CHANGED
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* agent-path — validate a config-supplied agent name before
|
|
2
|
+
* agent-path — validate a config-supplied agent name before you use it as a
|
|
3
3
|
* filesystem path component.
|
|
4
4
|
*
|
|
5
5
|
* The agent-state writer maps an agent name to a per-agent state filename.
|
|
6
|
-
* A name
|
|
7
|
-
* direct writes outside `~/.cache/fit/outpost/state/`. This
|
|
8
|
-
* and rejects
|
|
9
|
-
*
|
|
6
|
+
* A name that carries `/` or `..` segments would let a rewritten
|
|
7
|
+
* `scheduler.json` direct writes outside `~/.cache/fit/outpost/state/`. This
|
|
8
|
+
* module validates the name and rejects an unsafe one. It never sanitises the
|
|
9
|
+
* name silently. So an unexpected path segment surfaces as an intrusion
|
|
10
|
+
* signal. It does not become a quietly rewritten filename.
|
|
10
11
|
*/
|
|
11
12
|
|
|
12
|
-
/**
|
|
13
|
+
/**
|
|
14
|
+
* `agentNameToStatePrefix` raises this when an agent name cannot map to a
|
|
15
|
+
* safe state-file prefix.
|
|
16
|
+
*/
|
|
13
17
|
export class UnsafeAgentNameError extends Error {
|
|
14
18
|
/** @param {string} name */
|
|
15
19
|
constructor(name) {
|
package/src/agent-runner.js
CHANGED
|
@@ -15,14 +15,14 @@ import { resolvePrivilege, disclaimFor } from "./privilege.js";
|
|
|
15
15
|
import { buildSpawnEnv } from "./spawn-env.js";
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
|
-
*
|
|
19
|
-
* draft-side prose in a materialised agent definition
|
|
20
|
-
* posture record.
|
|
18
|
+
* The system-prompt directive the runner injects under the `brief` posture. It
|
|
19
|
+
* neutralises any draft-side prose in a materialised agent definition. It also
|
|
20
|
+
* forbids a write to the posture record.
|
|
21
21
|
*/
|
|
22
22
|
const BRIEF_DIRECTIVE =
|
|
23
23
|
"Adoption posture: brief. Run only read-and-brief work. Do not draft or " +
|
|
24
|
-
"send content on the user's behalf for delivery to anyone else
|
|
25
|
-
"or write files outside the knowledge base
|
|
24
|
+
"send content on the user's behalf for delivery to anyone else. Do not " +
|
|
25
|
+
"move or write files outside the knowledge base. Never write the posture " +
|
|
26
26
|
"record (~/.fit/outpost/posture.json).";
|
|
27
27
|
|
|
28
28
|
/** Spawn agent CLI processes, capture their output, and update agent state. */
|
|
@@ -41,11 +41,11 @@ export class AgentRunner {
|
|
|
41
41
|
|
|
42
42
|
/**
|
|
43
43
|
* @param {Object | (() => Object | Promise<{default?: Object}>)} spawn -
|
|
44
|
-
* The posix-spawn module, or a
|
|
45
|
-
* loader lets the Bun-FFI module load lazily
|
|
46
|
-
* that never
|
|
44
|
+
* The posix-spawn module, or a loader that returns it. The loader may be
|
|
45
|
+
* async. A loader lets the Bun-FFI module load lazily. So a plain `node`
|
|
46
|
+
* invocation that never wakes an agent does not pull in `bun:ffi`.
|
|
47
47
|
* @param {import('./state-manager.js').StateManager} stateManager
|
|
48
|
-
* @param {Function} logFn -
|
|
48
|
+
* @param {Function} logFn - The function that writes a log line
|
|
49
49
|
* @param {string} cacheDir - Cache directory for state files
|
|
50
50
|
* @param {import("@forwardimpact/libutil/runtime").Runtime} runtime
|
|
51
51
|
* Injected runtime bag (uses `fs` (async), `proc`, `clock`).
|
|
@@ -84,8 +84,8 @@ export class AgentRunner {
|
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
/**
|
|
87
|
-
* Resolve the injected spawn collaborator to the posix-spawn module
|
|
88
|
-
*
|
|
87
|
+
* Resolve the injected spawn collaborator to the posix-spawn module. On
|
|
88
|
+
* first use, invoke a loader thunk and unwrap it.
|
|
89
89
|
* @returns {Promise<Object>}
|
|
90
90
|
*/
|
|
91
91
|
async #resolveSpawn() {
|
|
@@ -97,7 +97,7 @@ export class AgentRunner {
|
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
/**
|
|
100
|
-
* Test whether a path exists,
|
|
100
|
+
* Test whether a path exists, through the async fs surface.
|
|
101
101
|
* @param {string} p
|
|
102
102
|
* @returns {Promise<boolean>}
|
|
103
103
|
*/
|
|
@@ -148,11 +148,12 @@ export class AgentRunner {
|
|
|
148
148
|
}
|
|
149
149
|
|
|
150
150
|
/**
|
|
151
|
-
* Resolve the spawn flags the recorded posture adds. Under `brief
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
151
|
+
* Resolve the spawn flags the recorded posture adds. Under `brief`, deny
|
|
152
|
+
* every draft-side skill by name and inject the brief directive. `brief` is
|
|
153
|
+
* also the default when no posture is recorded. The directive is a
|
|
154
|
+
* deterministic gate. The woken agent cannot override it under
|
|
155
|
+
* `bypassPermissions`. Under `brief+draft`, add nothing. This method reads
|
|
156
|
+
* the posture record. It never writes the record.
|
|
156
157
|
* @returns {Promise<string[]>} Extra args to append to the spawn argv.
|
|
157
158
|
*/
|
|
158
159
|
async #postureArgs() {
|
|
@@ -170,17 +171,20 @@ export class AgentRunner {
|
|
|
170
171
|
}
|
|
171
172
|
|
|
172
173
|
/**
|
|
173
|
-
* Validate the agent's kb path exists
|
|
174
|
+
* Validate that the agent's kb path exists. Spawn `claude --agent` with the
|
|
175
|
+
* prompt "Observe and act." Then update the agent state to active, idle, or
|
|
176
|
+
* failed.
|
|
174
177
|
* @param {string} agentName
|
|
175
178
|
* @param {Object} agent
|
|
176
179
|
* @param {Object} state
|
|
177
180
|
* @param {Record<string, string>} [configEnv] - Extra env vars from config
|
|
178
181
|
*/
|
|
179
182
|
async wake(agentName, agent, state, configEnv) {
|
|
180
|
-
// Resolve the mandatory privilege level before any work.
|
|
181
|
-
//
|
|
182
|
-
//
|
|
183
|
-
// root, so a spawned agent cannot raise
|
|
183
|
+
// Resolve the mandatory privilege level before any work. The runner is
|
|
184
|
+
// fail-closed on a missing or invalid level. It logs the problem and skips
|
|
185
|
+
// the wake. It never spawns an agent process with a guessed privilege. The
|
|
186
|
+
// level lives in the user-only trust root, so a spawned agent cannot raise
|
|
187
|
+
// its own.
|
|
184
188
|
let level;
|
|
185
189
|
try {
|
|
186
190
|
level = resolvePrivilege(agent);
|
|
@@ -196,13 +200,13 @@ export class AgentRunner {
|
|
|
196
200
|
}
|
|
197
201
|
|
|
198
202
|
if (!agent.kb) {
|
|
199
|
-
this.#log(`Agent ${agentName}: no "kb" specified
|
|
203
|
+
this.#log(`Agent ${agentName}: no "kb" specified. Skipped.`);
|
|
200
204
|
return;
|
|
201
205
|
}
|
|
202
206
|
const kbPath = this.#expandPath(agent.kb);
|
|
203
207
|
if (!(await this.#exists(kbPath))) {
|
|
204
208
|
this.#log(
|
|
205
|
-
`Agent ${agentName}: path "${kbPath}" does not exist
|
|
209
|
+
`Agent ${agentName}: path "${kbPath}" does not exist. Skipped.`,
|
|
206
210
|
);
|
|
207
211
|
return;
|
|
208
212
|
}
|
package/src/index.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
// Public entry point for @forwardimpact/outpost.
|
|
2
|
-
// Outpost is primarily a CLI
|
|
3
|
-
//
|
|
4
|
-
// src/outpost.js.
|
|
2
|
+
// Outpost is primarily a CLI. This file exists so the package conforms to the
|
|
3
|
+
// repo-wide layout contract. The runtime CLI dispatch lives in src/outpost.js.
|
|
5
4
|
export * from "./outpost.js";
|
package/src/kb-manager.js
CHANGED
|
@@ -6,7 +6,9 @@ import { join, dirname, resolve, basename } from "node:path";
|
|
|
6
6
|
import { homedir } from "node:os";
|
|
7
7
|
import { createLogger } from "@forwardimpact/libtelemetry";
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
import { LEGACY_ROOTS } from "./kb-validator.js";
|
|
10
|
+
|
|
11
|
+
/** Manage the knowledge base lifecycle: init, update, and settings merge. */
|
|
10
12
|
export class KBManager {
|
|
11
13
|
#fs;
|
|
12
14
|
#logger;
|
|
@@ -25,12 +27,13 @@ export class KBManager {
|
|
|
25
27
|
|
|
26
28
|
/**
|
|
27
29
|
* Resolve a knowledge-base name to its path under the XDG data home,
|
|
28
|
-
* `~/.local/share/fit/outpost/<name>`. The argument is a single path
|
|
29
|
-
* never an arbitrary filesystem path
|
|
30
|
-
* TCC-protected folders.
|
|
31
|
-
* same rule as `agent-path.js
|
|
32
|
-
*
|
|
33
|
-
*
|
|
30
|
+
* `~/.local/share/fit/outpost/<name>`. The argument is a single path
|
|
31
|
+
* segment. It is never an arbitrary filesystem path. So a provisioned KB
|
|
32
|
+
* always lands outside TCC-protected folders. This method validates the name
|
|
33
|
+
* against the same rule as `agent-path.js`. It does not sanitise the name. A
|
|
34
|
+
* name that carries `/`, `\`, `..`, NUL, or a leading `~` could steer the KB
|
|
35
|
+
* back inside `~/Documents` and reopen the TCC hole. So this method rejects
|
|
36
|
+
* the name. It never rewrites the name.
|
|
34
37
|
* @param {string} name - The KB name (e.g. `Team`, `personal`).
|
|
35
38
|
* @returns {string} Absolute path under the data home.
|
|
36
39
|
* @throws {Error} when `name` is empty, non-string, or an unsafe segment.
|
|
@@ -51,7 +54,7 @@ export class KBManager {
|
|
|
51
54
|
}
|
|
52
55
|
|
|
53
56
|
/**
|
|
54
|
-
* Test whether a path exists,
|
|
57
|
+
* Test whether a path exists, through the async fs surface.
|
|
55
58
|
* @param {string} p
|
|
56
59
|
* @returns {Promise<boolean>}
|
|
57
60
|
*/
|
|
@@ -94,7 +97,7 @@ export class KBManager {
|
|
|
94
97
|
}
|
|
95
98
|
|
|
96
99
|
/**
|
|
97
|
-
* Copy bundled files (CLAUDE.md, skills, agents) from template to a KB.
|
|
100
|
+
* Copy bundled files (CLAUDE.md, skills, agents) from the template to a KB.
|
|
98
101
|
* @param {string} tpl - Path to the template directory
|
|
99
102
|
* @param {string} dest - Path to the target knowledge base
|
|
100
103
|
* @returns {Promise<void>}
|
|
@@ -156,7 +159,7 @@ export class KBManager {
|
|
|
156
159
|
}
|
|
157
160
|
|
|
158
161
|
/**
|
|
159
|
-
* Merge template settings.json into the destination's settings.json.
|
|
162
|
+
* Merge the template settings.json into the destination's settings.json.
|
|
160
163
|
* @param {string} tpl - Template directory
|
|
161
164
|
* @param {string} dest - Knowledge base directory
|
|
162
165
|
* @returns {Promise<void>}
|
|
@@ -206,14 +209,23 @@ export class KBManager {
|
|
|
206
209
|
}
|
|
207
210
|
|
|
208
211
|
await this.#ensureDir(dest);
|
|
209
|
-
// Create the
|
|
210
|
-
//
|
|
211
|
-
//
|
|
212
|
-
//
|
|
213
|
-
|
|
212
|
+
// Create the tier directories and the personal `Briefings/` root only.
|
|
213
|
+
// The numbered tiers are the knowledge graph and the units of sharing;
|
|
214
|
+
// every other root entry is personal. The skills that write into the
|
|
215
|
+
// entity subdirectories (People, Organizations, ...) create them on
|
|
216
|
+
// demand inside each tier.
|
|
217
|
+
for (const d of [
|
|
218
|
+
"0-Draft",
|
|
219
|
+
"1-Management",
|
|
220
|
+
"2-Confidential",
|
|
221
|
+
"3-Team",
|
|
222
|
+
"4-Public",
|
|
223
|
+
"Briefings",
|
|
224
|
+
])
|
|
214
225
|
await this.#ensureDir(join(dest, d));
|
|
215
226
|
|
|
216
227
|
await this.copyBundledFiles(templateDir, dest);
|
|
228
|
+
await this.#installRegistry(templateDir, dest);
|
|
217
229
|
await this.#linkIntoDocuments(dest);
|
|
218
230
|
|
|
219
231
|
this.#logger.info(
|
|
@@ -223,12 +235,13 @@ export class KBManager {
|
|
|
223
235
|
}
|
|
224
236
|
|
|
225
237
|
/**
|
|
226
|
-
* Create a navigation symlink at `~/Documents/<name>`
|
|
238
|
+
* Create a navigation symlink at `~/Documents/<name>` that points to the KB.
|
|
227
239
|
* The KB data itself stays under the XDG data home, outside TCC-protected
|
|
228
|
-
* folders
|
|
229
|
-
* open from Finder.
|
|
230
|
-
*
|
|
231
|
-
*
|
|
240
|
+
* folders. The symlink is only a convenience pointer. It makes the KB easy
|
|
241
|
+
* to find and open from Finder. The method is best-effort. It leaves a
|
|
242
|
+
* pre-existing entry untouched. It logs any failure, for example when macOS
|
|
243
|
+
* denies write access to `~/Documents`. A failure is never fatal, because
|
|
244
|
+
* the KB is already provisioned at `dest`.
|
|
232
245
|
* @param {string} dest - Absolute path to the provisioned KB.
|
|
233
246
|
* @returns {Promise<void>}
|
|
234
247
|
*/
|
|
@@ -263,10 +276,52 @@ export class KBManager {
|
|
|
263
276
|
};
|
|
264
277
|
}
|
|
265
278
|
await this.copyBundledFiles(templateDir, dest);
|
|
279
|
+
await this.#installRegistry(templateDir, dest);
|
|
280
|
+
await this.#installMigrationGuide(templateDir, dest);
|
|
266
281
|
this.#logger.info(`\nKnowledge base updated: ${dest}`);
|
|
267
282
|
return { ok: true, value: { dest } };
|
|
268
283
|
}
|
|
269
284
|
|
|
285
|
+
/**
|
|
286
|
+
* Install the default `registry.yaml` when the KB has none. The registry
|
|
287
|
+
* is a personal surface humans edit, so this method never overwrites an
|
|
288
|
+
* existing one. `copyBundledFiles` copies named files only and never picks
|
|
289
|
+
* it up.
|
|
290
|
+
* @param {string} tpl - Template directory
|
|
291
|
+
* @param {string} dest - Knowledge base directory
|
|
292
|
+
* @returns {Promise<void>}
|
|
293
|
+
*/
|
|
294
|
+
async #installRegistry(tpl, dest) {
|
|
295
|
+
const src = join(tpl, "registry.yaml");
|
|
296
|
+
const destPath = join(dest, "registry.yaml");
|
|
297
|
+
if (!(await this.#exists(src)) || (await this.#exists(destPath))) return;
|
|
298
|
+
await this.#fs.copyFile(src, destPath);
|
|
299
|
+
this.#logger.info(` Installed registry.yaml`);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Install MIGRATION.md while the KB still carries a legacy layout
|
|
304
|
+
* (`Knowledge/` or `Drafts/` at the root). A conforming KB never receives
|
|
305
|
+
* it, and this method removes nothing.
|
|
306
|
+
* @param {string} tpl - Template directory
|
|
307
|
+
* @param {string} dest - Knowledge base directory
|
|
308
|
+
* @returns {Promise<void>}
|
|
309
|
+
*/
|
|
310
|
+
async #installMigrationGuide(tpl, dest) {
|
|
311
|
+
let legacy = false;
|
|
312
|
+
for (const marker of LEGACY_ROOTS) {
|
|
313
|
+
if (await this.#exists(join(dest, marker))) legacy = true;
|
|
314
|
+
}
|
|
315
|
+
if (!legacy) return;
|
|
316
|
+
await this.#fs.copyFile(
|
|
317
|
+
join(tpl, "MIGRATION.md"),
|
|
318
|
+
join(dest, "MIGRATION.md"),
|
|
319
|
+
);
|
|
320
|
+
this.#logger.info(
|
|
321
|
+
` Installed MIGRATION.md — this knowledge base carries the legacy layout. Follow it to migrate to tiers.`,
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
|
|
270
325
|
/**
|
|
271
326
|
* @param {string} p
|
|
272
327
|
* @returns {string}
|