fdeops 3.9.17 → 3.9.18
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 +3 -1
- package/bin/fde.js +83 -0
- package/package.json +1 -1
- package/skills/fde/SKILL.md +1 -1
- package/skills/fde/references/discover.md +1 -1
- package/skills/fde/references/stakeholder-radar.md +2 -0
- package/templates/.fde/stakeholders.md +4 -2
- package/templates/.fde/terrain.md +2 -1
package/README.md
CHANGED
|
@@ -7,7 +7,9 @@
|
|
|
7
7
|
[](LICENSE)
|
|
8
8
|
[](https://nodejs.org)
|
|
9
9
|
|
|
10
|
-
**Memory + methodology + skills, in one kit.** Skill packs teach your AI agent how to build. None of them remember who the client is, what was decided, or what's safe to ship. FDEOps adds the missing layer: a private fieldbook per engagement (`.fde/`), a field methodology (land → close), and one `@fde` skill that routes it all.
|
|
10
|
+
**Memory + methodology + skills, in one kit.** Skill packs teach your AI agent how to build. None of them remember who the client is, what was decided, or what's safe to ship. FDEOps adds the missing layer: a private fieldbook per engagement (`.fde/`), a field methodology (land → close), and one `@fde` skill that routes it all.
|
|
11
|
+
|
|
12
|
+
Built for Forward Deployed Engineers, and anyone embedded in client work: consultants, agency developers, solutions architects, fractional CTOs. Feels like a second brain; behaves like a defensible record (dated, sourced, yours).
|
|
11
13
|
|
|
12
14
|
```
|
|
13
15
|
land discover plan build ship close
|
package/bin/fde.js
CHANGED
|
@@ -1671,9 +1671,92 @@ function collectDoctorIssues(eng) {
|
|
|
1671
1671
|
`${dupes.length} duplicate open-risk cluster(s) (e.g. "${sample}${sample.length >= 60 ? '…' : ''}") - consolidate or retire echoes in risks.md`
|
|
1672
1672
|
)
|
|
1673
1673
|
}
|
|
1674
|
+
// Failure-path (exception-led operating map): required once past discover.
|
|
1675
|
+
// Land seeds; discover fills; plan+ without a real break→owner row is wallpaper.
|
|
1676
|
+
if (/^(plan|build|ship|close)$/.test(s.phase) && !hasOperatingMapContent(eng)) {
|
|
1677
|
+
issues.push(
|
|
1678
|
+
`phase is ${s.phase} with empty operating map - fill terrain.md ## Operating map (exception-led): break → who notices → workaround → evidence`
|
|
1679
|
+
)
|
|
1680
|
+
}
|
|
1681
|
+
const aliases = findAmbiguousStakeholders(eng)
|
|
1682
|
+
if (aliases.length) {
|
|
1683
|
+
const sample = aliases[0].forms.slice(0, 3).join(' / ')
|
|
1684
|
+
issues.push(
|
|
1685
|
+
`${aliases.length} stakeholder identity cluster(s) (e.g. "${sample}") - same person under different names? consolidate in stakeholders.md`
|
|
1686
|
+
)
|
|
1687
|
+
}
|
|
1674
1688
|
return issues
|
|
1675
1689
|
}
|
|
1676
1690
|
|
|
1691
|
+
// True when ## Operating map has at least one real exception row (not the empty template).
|
|
1692
|
+
function hasOperatingMapContent(eng) {
|
|
1693
|
+
const terrain = stripTemplateNoise(readClean(eng, 'terrain.md'))
|
|
1694
|
+
const body = sectionBody(terrain, 'Operating map')
|
|
1695
|
+
if (!body.trim()) return false
|
|
1696
|
+
const table = parseMdTable(body)
|
|
1697
|
+
if (table) {
|
|
1698
|
+
const exIdx = colIndex(table.headers, /exception|break/i)
|
|
1699
|
+
const idx = exIdx !== -1 ? exIdx : 0
|
|
1700
|
+
for (const row of table.rows) {
|
|
1701
|
+
const cell = (row[idx] || '').trim()
|
|
1702
|
+
if (cell && !/^unknown/i.test(cell)) return true
|
|
1703
|
+
}
|
|
1704
|
+
}
|
|
1705
|
+
for (const raw of body.split('\n')) {
|
|
1706
|
+
const t = raw.trim().replace(/^[-*]\s+/, '')
|
|
1707
|
+
if (!t || t.startsWith('#') || t.startsWith('|') || /^\*\*/.test(t)) continue
|
|
1708
|
+
if (t.length >= 8 && !/^unknown/i.test(t)) return true
|
|
1709
|
+
}
|
|
1710
|
+
return false
|
|
1711
|
+
}
|
|
1712
|
+
|
|
1713
|
+
// Near-duplicate stakeholder forms sharing a first-name key (Denise vs Denise Chen).
|
|
1714
|
+
function findAmbiguousStakeholders(eng) {
|
|
1715
|
+
const forms = []
|
|
1716
|
+
const md = readClean(eng, 'stakeholders.md')
|
|
1717
|
+
const table = parseMdTable(md)
|
|
1718
|
+
if (table) {
|
|
1719
|
+
const nameIdx = colIndex(table.headers, /name|who/i)
|
|
1720
|
+
if (nameIdx !== -1) {
|
|
1721
|
+
for (const row of table.rows) {
|
|
1722
|
+
const name = (row[nameIdx] || '').trim()
|
|
1723
|
+
if (!name || name.length < 2) continue
|
|
1724
|
+
forms.push(name)
|
|
1725
|
+
}
|
|
1726
|
+
}
|
|
1727
|
+
}
|
|
1728
|
+
for (const h of parseSignalHistoryEntries(eng)) {
|
|
1729
|
+
const name = displayNameFromSignalText(h.text)
|
|
1730
|
+
if (name && name.length >= 2 && !/^anon:/i.test(name)) forms.push(name)
|
|
1731
|
+
}
|
|
1732
|
+
const byKey = new Map()
|
|
1733
|
+
for (const name of forms) {
|
|
1734
|
+
const key = signalSubjectKey(name)
|
|
1735
|
+
if (!key || key.startsWith('anon:')) continue
|
|
1736
|
+
const norm = name.replace(/\s+/g, ' ').trim().toLowerCase()
|
|
1737
|
+
if (!byKey.has(key)) byKey.set(key, new Set())
|
|
1738
|
+
byKey.get(key).add(norm)
|
|
1739
|
+
}
|
|
1740
|
+
const clusters = []
|
|
1741
|
+
for (const [key, set] of byKey) {
|
|
1742
|
+
if (set.size < 2) continue
|
|
1743
|
+
// Prefer clusters where forms aren't just identical casing - already lowercased.
|
|
1744
|
+
// Require at least one multi-token form vs a shorter form (Denise / Denise Chen).
|
|
1745
|
+
const list = [...set]
|
|
1746
|
+
const hasLong = list.some(f => f.split(/\s+/).length >= 2)
|
|
1747
|
+
const hasShort = list.some(f => f.split(/\s+/).length === 1)
|
|
1748
|
+
if (hasLong && hasShort) {
|
|
1749
|
+
clusters.push({ key, forms: list })
|
|
1750
|
+
continue
|
|
1751
|
+
}
|
|
1752
|
+
// Or two multi-token forms that share first token but differ later (Denise Chen / Denise C.)
|
|
1753
|
+
if (list.length >= 2 && list.every(f => f.split(/\s+/).length >= 2)) {
|
|
1754
|
+
clusters.push({ key, forms: list })
|
|
1755
|
+
}
|
|
1756
|
+
}
|
|
1757
|
+
return clusters
|
|
1758
|
+
}
|
|
1759
|
+
|
|
1677
1760
|
// Strip template comments / italic *(hints)* so doctor does not treat stubs as filled.
|
|
1678
1761
|
function stripTemplateNoise(md) {
|
|
1679
1762
|
return String(md || '')
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fdeops",
|
|
3
|
-
"version": "3.9.
|
|
3
|
+
"version": "3.9.18",
|
|
4
4
|
"description": "Field kit for engineers embedded in client work - a real CLI (recon, memory, portfolio), one @fde skill with field judgment on top, and hooks that make it automatic. Claude Code plugin and any agent that loads skills.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"fdeops": "bin/install.js",
|
package/skills/fde/SKILL.md
CHANGED
|
@@ -88,7 +88,7 @@ When NOT to interrogate or challenge: unambiguous one-liners, mechanical ops, FD
|
|
|
88
88
|
| "Draft the sponsor update" / how are we doing | `fde status` then follow `references/status.md` for the narrative |
|
|
89
89
|
| "Log that they went quiet" / trust signal | `fde log contact "…" --signal amber\|green\|red`. If they already named the color ("log that as amber"), that is the confirm — write it. If they only described the situation, playback the color once, then write. |
|
|
90
90
|
| Want the HTML fieldbook | `fde dashboard` |
|
|
91
|
-
| "Clean up the fieldbook" / hygiene / memory feels messy | `fde doctor` - walk issues in plain language; propose fixes; never auto-rewrite without confirm. Contradictions need judgment (brief vs reality) - doctor is structural; you handle meaning. |
|
|
91
|
+
| "Clean up the fieldbook" / hygiene / memory feels messy | `fde doctor` - walk issues in plain language; propose fixes; never auto-rewrite without confirm. Includes structural gaps: empty operating map (plan+), stakeholder name forks (Denise vs Denise Chen), duplicates, ship/close risks. Contradictions need judgment (brief vs reality) - doctor is structural; you handle meaning. |
|
|
92
92
|
| "Scrub this secret / redact that token" (buried line, not just last write) | `fde redact <term>` preview, then `fde redact <term> --apply` after confirm. Undo is last-write only; redact is for buried lines. Remind them to rotate the real credential. |
|
|
93
93
|
|
|
94
94
|
**The debrief verb.** Highest-frequency loop. When the FDE shares notes or says "debrief": **you** run the smart path (write notes to a temp file if needed). `--smart` writes a propose file via deterministic heuristics (existing prefixes + light keywords); authentic rambling notes often land mostly in context until **you** rewrite lines with type prefixes. Show the proposed routing in plain language. Only `--apply` (or pipe prefixed lines) after they confirm. Never ask them to run the CLI. Detail: `references/debrief.md`.
|
|
@@ -92,7 +92,7 @@ The real spec is what people **do** when the system fails - not what the slide d
|
|
|
92
92
|
- **The hesitation.** When someone says "well, there's also this other thing we do…" - stop them, ask them to finish. The main story is what they're comfortable explaining; the hesitation is the real problem.
|
|
93
93
|
- **"Which part of the codebase do you least want to touch?"** The answer is unanimous and it's the load-bearing wall. Check it against your churn scan - when the human answer and the churn data agree, that's your first map landmark.
|
|
94
94
|
- **Shadow AI.** Someone pasting data into ChatGPT to cope = a real unmet need + an uncontrolled data risk. Note both.
|
|
95
|
-
- **Exception-led operating map.** For each real break (not the slide-deck process): what fails, who notices first, what they do today, and which artifact is trusted in that moment. Prefer exceptions over happy-path swimlanes — the workaround is the operating system. Write rows under `terrain.md` → `## Operating map (exception-led)`. If the section is missing on an older engagement, add it; never regenerate the rest of terrain. When AI is in play, also fill `## Intelligence placement` (deterministic vs LLM judgement vs human approve).
|
|
95
|
+
- **Exception-led operating map.** For each real break (not the slide-deck process): what fails, who notices first, what they do today, and which artifact is trusted in that moment. Prefer exceptions over happy-path swimlanes — the workaround is the operating system. Write rows under `terrain.md` → `## Operating map (exception-led)`. If the section is missing on an older engagement, add it; never regenerate the rest of terrain. When AI is in play, also fill `## Intelligence placement` (deterministic vs LLM judgement vs human approve). **`fde doctor` requires at least one filled exception row before plan/build/ship/close** — empty map after discover is a hygiene fail, not optional polish.
|
|
96
96
|
|
|
97
97
|
## Method - part 3: workshop facilitation
|
|
98
98
|
|
|
@@ -28,6 +28,8 @@ The org chart tells you who reports to whom. The stakeholder radar tells you who
|
|
|
28
28
|
|
|
29
29
|
**3. The 48-hour rule.** A stakeholder who goes amber has roughly 48 hours before they go red. A stakeholder who goes red is already escalating above you. Respond same-day to amber signals - not with more delivery, with a conversation.
|
|
30
30
|
|
|
31
|
+
**3b. One name per person.** If the table says "Denise Chen" and Signal history says "Denise" or "D. Chen", trust keys fork and prep lies. Consolidate to one spelling. `fde doctor` flags these identity clusters — treat that as a fix, not a nit.
|
|
32
|
+
|
|
31
33
|
**4. Detect the invisible escalation.** Three markers:
|
|
32
34
|
- Questions shift from "what are you building" to "when will it be done" - someone above is asking.
|
|
33
35
|
- A meeting gets shortened or cancelled - they're meeting without you.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# Stakeholders
|
|
2
2
|
|
|
3
|
-
<!-- Champions, blockers, veto power. Trust signals: quiet = escalate.
|
|
3
|
+
<!-- Champions, blockers, veto power. Trust signals: quiet = escalate.
|
|
4
|
+
One row per real person - if Denise / Denise Chen / D. Chen appear, consolidate. -->
|
|
4
5
|
|
|
5
6
|
| Name | Role | Stance | Notes |
|
|
6
7
|
|------|------|--------|-------|
|
|
@@ -14,5 +15,6 @@
|
|
|
14
15
|
<!-- `fde log contact --signal <color>` and `fde debrief` write dated tokens here.
|
|
15
16
|
fde status/receipts read the LATEST dated [signal:...] token in this section
|
|
16
17
|
to drive the trust column - do not delete this heading, and if you rewrite
|
|
17
|
-
this file as an artifact, keep this section's entries intact.
|
|
18
|
+
this file as an artifact, keep this section's entries intact.
|
|
19
|
+
Prefer the same Name spelling as the table so trust keys don't fork. -->
|
|
18
20
|
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
|
|
9
9
|
## Operating map (exception-led)
|
|
10
10
|
|
|
11
|
-
<!-- How work actually runs when the happy path fails. Fill in discover; leave blank until heard/seen.
|
|
11
|
+
<!-- How work actually runs when the happy path fails. Fill in discover; leave blank until heard/seen.
|
|
12
|
+
fde doctor requires ≥1 real exception row before plan/build/ship/close. -->
|
|
12
13
|
|
|
13
14
|
| Exception / break | Who notices first | What they do today (workaround) | System of record then | Blast if wrong | Evidence |
|
|
14
15
|
|-------------------|-------------------|---------------------------------|-----------------------|----------------|----------|
|