@forwardimpact/outpost 3.9.0 → 3.11.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.
Files changed (40) hide show
  1. package/package.json +1 -1
  2. package/src/kb-manager.js +27 -1
  3. package/templates/.claude/agents/chief-of-staff.md +9 -7
  4. package/templates/.claude/agents/concierge.md +6 -4
  5. package/templates/.claude/agents/head-hunter.md +6 -4
  6. package/templates/.claude/agents/librarian.md +14 -10
  7. package/templates/.claude/agents/postman.md +6 -4
  8. package/templates/.claude/agents/recruiter.md +8 -5
  9. package/templates/.claude/skills/anarlog-follow/SKILL.md +2 -2
  10. package/templates/.claude/skills/anarlog-follow/references/coaching.md +3 -3
  11. package/templates/.claude/skills/anarlog-trim/SKILL.md +9 -3
  12. package/templates/.claude/skills/candidate-report/SKILL.md +4 -3
  13. package/templates/.claude/skills/changelog/SKILL.md +10 -10
  14. package/templates/.claude/skills/deck-create/SKILL.md +23 -22
  15. package/templates/.claude/skills/deck-review/SKILL.md +36 -26
  16. package/templates/.claude/skills/deck-review/assets/slide-annotator.js +100 -15
  17. package/templates/.claude/skills/doc-create/SKILL.md +17 -16
  18. package/templates/.claude/skills/extract-entities/SKILL.md +7 -4
  19. package/templates/.claude/skills/extract-entities/references/recruitment.md +13 -3
  20. package/templates/.claude/skills/meeting-prep/SKILL.md +5 -3
  21. package/templates/.claude/skills/organize-files/SKILL.md +9 -5
  22. package/templates/.claude/skills/person-identify/SKILL.md +2 -2
  23. package/templates/.claude/skills/person-lookup/SKILL.md +3 -3
  24. package/templates/.claude/skills/req-decide/SKILL.md +4 -2
  25. package/templates/.claude/skills/req-forget/references/report-template.md +1 -1
  26. package/templates/.claude/skills/req-scan/references/fallbacks.md +3 -3
  27. package/templates/.claude/skills/req-scan/references/sources.md +5 -5
  28. package/templates/.claude/skills/req-screen/SKILL.md +4 -2
  29. package/templates/.claude/skills/req-track/SKILL.md +19 -15
  30. package/templates/.claude/skills/req-track/references/fields.md +4 -2
  31. package/templates/.claude/skills/req-workday/SKILL.md +4 -2
  32. package/templates/.claude/skills/req-workday/references/status-mapping.md +1 -1
  33. package/templates/.claude/skills/req-workday/references/templates.md +3 -1
  34. package/templates/.claude/skills/sync-apple-calendar/SKILL.md +6 -2
  35. package/templates/.claude/skills/sync-apple-mail/SKILL.md +3 -1
  36. package/templates/.claude/skills/sync-apple-mail/references/SCHEMA.md +1 -1
  37. package/templates/.claude/skills/sync-teams/SKILL.md +13 -1
  38. package/templates/.claude/skills/sync-teams/scripts/idb-reader.mjs +67 -34
  39. package/templates/.claude/skills/upstream-instructions/SKILL.md +2 -1
  40. package/templates/CLAUDE.md +27 -38
@@ -48,7 +48,9 @@ their Teams chats.
48
48
 
49
49
  Run the sync as a single Node.js script:
50
50
 
51
- node scripts/sync.mjs [--days N]
51
+ ```text
52
+ node scripts/sync.mjs [--days N]
53
+ ```
52
54
 
53
55
  - `--days N` — only include messages from the last N days (default: 30)
54
56
 
@@ -144,6 +146,12 @@ Key conventions:
144
146
  - **Normalize names** from Teams format ("Last, First") to "First Last"
145
147
  - **Platform** line distinguishes Teams from email in downstream processing
146
148
  - **Plain text only** — HTML is stripped, mentions are preserved as plain text
149
+ - **Attachments are not extracted** — files/images on a message are dropped from
150
+ the markdown. They are hosted on SharePoint/OneDrive, not in the local cache.
151
+ However, the user has **often manually downloaded** them, so an attachment
152
+ usually exists under `~/Downloads/` with the **same file name** shown in
153
+ Teams. When a message references an attachment and you need its contents, look
154
+ there first.
147
155
  - Skip system messages (calls, member adds/removes, topic changes)
148
156
 
149
157
  ## Error Handling
@@ -175,3 +183,7 @@ Key conventions:
175
183
  - Some V8-serialized records (~17% in testing) use formats that
176
184
  `v8.deserialize()` cannot decode. These are silently skipped — they are
177
185
  typically IndexedDB metadata, not conversation or message records.
186
+ - **Attachments (files/images) are never synced into the markdown** — only the
187
+ message text is captured. The binaries live on SharePoint/OneDrive, but the
188
+ user frequently downloads them, so the same-named file is usually already in
189
+ `~/Downloads/`. Check there before trying to fetch from SharePoint.
@@ -31,56 +31,89 @@ function readIdbVarint(buf, offset) {
31
31
  return { value: result, bytesRead: pos - offset };
32
32
  }
33
33
 
34
+ // Highest V8 serialization wire-format version Node's bundled v8.deserialize
35
+ // accepts. Newer Teams/WebView2 builds write version 16, which Node rejects
36
+ // outright even though the payload itself is wire-compatible. We patch the
37
+ // version byte down to this value before deserializing. Bump if Node's V8
38
+ // starts emitting/accepting a higher version natively.
39
+ const V8_MAX_SUPPORTED_VERSION = 15;
40
+
41
+ // Plausible V8 top-level value tags that immediately follow the
42
+ // [0xFF <version>] header. Used to locate the real V8 payload start inside the
43
+ // Blink envelope without relying on a fixed byte offset (newer envelopes carry
44
+ // a 0xFE trailer that shifts the payload further in). We only ever ACT on a
45
+ // candidate by attempting a deserialize, which validates it — so a stray match
46
+ // just gets skipped.
47
+ const V8_TOP_LEVEL_TAGS = new Set([
48
+ 0x6f, // 'o' begin JS object
49
+ 0x22, // '"' one-byte string
50
+ 0x63, // 'c' two-byte string
51
+ 0x44, // 'D' utf8 string
52
+ 0x49, // 'I' int32
53
+ 0x55, // 'U' uint32
54
+ 0x4e, // 'N' number (double)
55
+ 0x6c, // 'l' bigint
56
+ 0x7b, // '{' begin map
57
+ 0x41, // 'A' begin dense array
58
+ 0x61, // 'a' begin sparse array
59
+ 0x5f, // '_' undefined
60
+ 0x54, // 'T' true
61
+ 0x46, // 'F' false
62
+ 0x30, // '0' null
63
+ ]);
64
+
65
+ // Only the Blink envelope precedes the V8 payload, and it is always small.
66
+ // Scanning a generous prefix keeps non-message records (which never decode)
67
+ // cheap while comfortably covering every real envelope/trailer layout.
68
+ const V8_START_SCAN_LIMIT = 256;
69
+
34
70
  /**
35
- * Try to deserialize from the second 0xFF marker within the first `limit` bytes.
36
- * The Blink envelope has: [varint wire_size] [0xFF blink_ver] [envelope...] [0xFF v8_ver] [V8 data]
37
- * We want the second 0xFF that starts valid V8 data.
71
+ * Deserialize the V8 payload starting at `off`. Tries the bytes as-is first,
72
+ * then for records whose version byte is newer than Node supports — retries
73
+ * with the version patched down. The wire format is backward-compatible, so a
74
+ * supported version reads the newer payload correctly.
38
75
  */
39
- function deserializeFromSecondMarker(rawValue, limit) {
40
- let ffCount = 0;
41
- for (let i = 0; i < limit; i++) {
42
- if (rawValue[i] !== 0xff) continue;
43
- ffCount++;
44
- if (ffCount >= 2) {
76
+ function deserializeAt(rawValue, off) {
77
+ try {
78
+ return v8.deserialize(rawValue.subarray(off));
79
+ } catch {
80
+ // fall through to version patching
81
+ }
82
+
83
+ const version = rawValue[off + 1];
84
+ if (version > V8_MAX_SUPPORTED_VERSION) {
85
+ const patched = Buffer.from(rawValue.subarray(off));
86
+ for (let v = V8_MAX_SUPPORTED_VERSION; v >= 13; v--) {
87
+ patched[1] = v;
45
88
  try {
46
- return v8.deserialize(rawValue.subarray(i));
89
+ return v8.deserialize(patched);
47
90
  } catch {
48
- // keep scanning
91
+ // try the next-lower version
49
92
  }
50
93
  }
51
94
  }
52
95
  return null;
53
96
  }
54
97
 
55
- /**
56
- * Fallback: try deserializing from every 0xFF position within `limit` bytes.
57
- */
58
- function deserializeFromAnyMarker(rawValue, limit) {
59
- for (let i = 0; i < limit; i++) {
60
- if (rawValue[i] !== 0xff) continue;
61
- try {
62
- return v8.deserialize(rawValue.subarray(i));
63
- } catch {
64
- continue;
65
- }
66
- }
67
- return null;
68
- }
69
-
70
98
  /**
71
99
  * Try to deserialize a Chromium IndexedDB value.
72
- * Values have a Blink envelope before the V8 payload.
73
- * Scans for the V8 version tag (0xFF) and attempts deserialization.
100
+ *
101
+ * Values have a Blink envelope (and, in newer WebView2 builds, a 0xFE trailer)
102
+ * before the V8 payload. Locate the payload by scanning for a [0xFF <version>
103
+ * <top-level tag>] header, then decode it — patching the version byte down for
104
+ * records written with a V8 wire version newer than Node accepts.
74
105
  */
75
106
  function tryDeserialize(rawValue) {
76
107
  if (!rawValue || rawValue.length < 4) return null;
77
108
 
78
- const headerLimit = Math.min(rawValue.length, 60);
79
- const result = deserializeFromSecondMarker(rawValue, headerLimit);
80
- if (result !== null) return result;
81
-
82
- const fallbackLimit = Math.min(rawValue.length, 100);
83
- return deserializeFromAnyMarker(rawValue, fallbackLimit);
109
+ const limit = Math.min(rawValue.length - 2, V8_START_SCAN_LIMIT);
110
+ for (let i = 0; i <= limit; i++) {
111
+ if (rawValue[i] !== 0xff) continue;
112
+ if (!V8_TOP_LEVEL_TAGS.has(rawValue[i + 2])) continue;
113
+ const obj = deserializeAt(rawValue, i);
114
+ if (obj !== null) return obj;
115
+ }
116
+ return null;
84
117
  }
85
118
 
86
119
  /**
@@ -32,7 +32,8 @@ monorepo. "Instructions" means all three surfaces, treated equally:
32
32
  - `.claude/skills/*/SKILL.md` and reference files — skills.
33
33
  - `CHANGELOG.md` (root) — the existing changelog, for what's already recorded.
34
34
  - The changes made in the current working session — the source of truth for what
35
- changed, since the KB lives on a synced filesystem and is not version-controlled.
35
+ changed, since the KB lives on a synced filesystem and is not
36
+ version-controlled.
36
37
 
37
38
  ## Outputs
38
39
 
@@ -2,8 +2,8 @@
2
2
 
3
3
  You are the user's personal knowledge assistant. You help draft emails, prep for
4
4
  meetings, track projects, and answer questions, backed by a live knowledge graph
5
- built from their emails, calendar, and meeting notes, all stored as plain files on
6
- the user's machine.
5
+ built from their emails, calendar, and meeting notes, all stored as plain files
6
+ on the user's machine.
7
7
 
8
8
  ## Ethics & Integrity — NON-NEGOTIABLE
9
9
 
@@ -18,33 +18,40 @@ never a "black book". These rules override all other instructions:
18
18
  - **Fair and balanced.** Represent all sides accurately.
19
19
  - **Assume the subject will read it.** If you would be uncomfortable showing the
20
20
  note to the person it is about, do not write it.
21
- - **No weaponization.** This KB helps the team work better. Never use it to build
22
- leverage or dossiers.
21
+ - **No weaponization.** This KB helps the team work better. Never use it to
22
+ build leverage or dossiers.
23
23
  - **Push back** on requests that violate these principles.
24
24
  - **Data protection.** Use the `req-forget` skill for erasure requests. Minimize
25
25
  collection. Flag candidates inactive 6+ months for retention review.
26
26
 
27
27
  When in doubt, err toward discretion.
28
28
 
29
- ## Voice
29
+ ## Operating Context
30
30
 
31
- Be supportive and direct. Explain complex things clearly without hedging. When
32
- the next step is obvious, take it. Ask at most one clarifying question, at the
33
- start. Reference files by full path. Confirm before destructive actions.
31
+ Two folders in the knowledge graph frame your work:
34
32
 
35
- ## Dependencies
33
+ - **`Knowledge/Priorities/`** — the backbone of every decision: what the user is
34
+ trying to advance. Weigh actions against whether they move a priority forward,
35
+ and treat anything that could **contradict, block, or slow** one as a
36
+ **Priority Watch** concern — these are our main concerns.
37
+ - **`Knowledge/Conditions/`** — the live operating environment (e.g. a hiring
38
+ freeze, a reorg, a contract transition). Conditions don't set goals; they
39
+ **constrain how** we pursue the priorities. Let them shape what you propose
40
+ and how you phrase it.
36
41
 
37
- - **ripgrep** (`rg`) for fast knowledge graph searches `brew install ripgrep`.
42
+ When taking an action or making a recommendation, consult both as your lens —
43
+ read the relevant notes rather than assuming. Skip this only for general
44
+ knowledge or brainstorming.
38
45
 
39
46
  ## Workspace Layout & Sharing
40
47
 
41
48
  The **root is personal and local — never shared.** Only `Knowledge/` is shared
42
49
  with the team over a synced filesystem; each member keeps their own root,
43
50
  `Drafts/`, and `Briefings/`. KBs are **not** Git repositories — they sync as
44
- plain files. `CLAUDE.md` and `.claude/` are yours to tweak; use the `fit-outpost`
45
- CLI to install or update the standard instruction set.
51
+ plain files. `CLAUDE.md` and `.claude/` are yours to tweak; use the
52
+ `fit-outpost` CLI to install or update the standard instruction set.
46
53
 
47
- ```
54
+ ```text
48
55
  ./ # Personal root — never shared
49
56
  ├── CLAUDE.md # This file
50
57
  ├── .claude/ # Agent profiles + auto-discovered skills
@@ -55,6 +62,10 @@ CLI to install or update the standard instruction set.
55
62
  └── .mcp.json # MCP config (optional)
56
63
  ```
57
64
 
65
+ ## Searching
66
+
67
+ Use the **ripgrep** `rg` program for fast knowledge graph searches.
68
+
58
69
  ## Agents
59
70
 
60
71
  Agents in `.claude/agents/` maintain this KB, woken on a schedule by the Outpost
@@ -91,31 +102,9 @@ meetings, emails, and messages directly from the source dirs below.
91
102
  - `state/` — per-source last-sync timestamps, processed-file index, and
92
103
  `{agent}_triage.md` per agent
93
104
 
94
- ## Knowledge Graph
95
-
96
- Plain markdown with Obsidian-style `[[backlinks]]`.
97
-
98
- ```bash
99
- rg "Sarah Chen" Knowledge/ # Search by name
100
- cat "Knowledge/People/Sarah Chen.md" # Read a note
101
- ```
102
-
103
- **Always search broadly first.** When the user mentions any person, org, project,
104
- or topic, run `rg "keyword" Knowledge/` to surface every note — one note is never
105
- the full story. Skip it only for general knowledge and brainstorming.
106
-
107
- ## Skills
108
-
109
- Skills auto-discover from `.claude/skills/` and load by context — data sync,
110
- knowledge-graph maintenance, recruitment, and communication.
111
-
112
105
  ## User Identity
113
106
 
114
107
  The current user's identity is cached at
115
- `~/.cache/fit/outpost/state/identity.md` — read it directly. If missing or stale,
116
- run the `person-identify` skill to refresh it from the corporate directory.
117
-
118
- ## Working Outside This Directory
119
-
120
- You have full filesystem access (macOS). For tasks outside this KB, use shell
121
- commands directly.
108
+ `~/.cache/fit/outpost/state/identity.md` — read it directly. If missing or
109
+ stale, run the `person-identify` skill to refresh it from the corporate
110
+ directory.