@nebutra/founder-cemetery 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/.nebutra/debug/content-store.jsonl +5 -0
- package/.nebutra/debug/event-log.jsonl +1 -0
- package/.nebutra/debug/founder-cemetery.jsonl +8 -0
- package/.turbo/turbo-build.log +22 -0
- package/.turbo/turbo-test.log +16 -0
- package/.turbo/turbo-typecheck.log +4 -0
- package/CHANGELOG.md +8 -0
- package/LICENSE +676 -0
- package/README.md +28 -0
- package/dist/chunk-X5WY4XBS.js +193 -0
- package/dist/chunk-X5WY4XBS.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +41 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +84 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/examples/doctor.ts +11 -0
- package/examples/memorial.ts +19 -0
- package/examples/quickstart.ts +16 -0
- package/package.json +64 -0
- package/plays/close_company/SKILL.md +23 -0
- package/src/cli.ts +33 -0
- package/src/index.test.ts +104 -0
- package/src/index.ts +309 -0
- package/tsconfig.json +9 -0
- package/tsup.config.ts +9 -0
package/README.md
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# @nebutra/founder-cemetery
|
|
2
|
+
|
|
3
|
+
Status: **WIP**
|
|
4
|
+
|
|
5
|
+
Ethical close-company flow, postmortem analysis, lesson extraction, and memorial
|
|
6
|
+
publication artifacts.
|
|
7
|
+
|
|
8
|
+
## Boundary
|
|
9
|
+
|
|
10
|
+
This package does not delete companies. It starts with pause, then lets the
|
|
11
|
+
founder choose archive or memorial publication with consent and a cooling-off
|
|
12
|
+
period.
|
|
13
|
+
|
|
14
|
+
## Commands
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pnpm founder-cemetery:doctor
|
|
18
|
+
pnpm founder-cemetery:quickstart
|
|
19
|
+
pnpm founder-cemetery:debug
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Current Closure
|
|
23
|
+
|
|
24
|
+
- Pause-first closing flow.
|
|
25
|
+
- Deterministic death-cause inference over timeline summaries.
|
|
26
|
+
- Evidence-backed lesson records.
|
|
27
|
+
- Memorial artifacts with explicit consent.
|
|
28
|
+
- Cooling-off metadata for publication.
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import { mkdir } from "fs/promises";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
import { appendCapabilityDebug, readCapabilityDebug } from "@nebutra/capability-kit/debug";
|
|
5
|
+
import { ContentStore } from "@nebutra/content-store";
|
|
6
|
+
import { assertPublicDisclosureSafe } from "@nebutra/ecosystem-safety";
|
|
7
|
+
import { CapabilityError } from "@nebutra/errors";
|
|
8
|
+
import { EventLog } from "@nebutra/event-log";
|
|
9
|
+
import { assetId } from "@nebutra/generation-context";
|
|
10
|
+
function requireTenant(value) {
|
|
11
|
+
if (!value?.trim()) {
|
|
12
|
+
throw new CapabilityError("founder-cemetery", "Founder Cemetery requires tenant context", {
|
|
13
|
+
suggestion: "Pass tenantId so closure artifacts stay tenant-scoped.",
|
|
14
|
+
statusCode: 400
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
return value;
|
|
18
|
+
}
|
|
19
|
+
function slugify(value) {
|
|
20
|
+
return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64);
|
|
21
|
+
}
|
|
22
|
+
function inferCause(evidence) {
|
|
23
|
+
const combined = evidence.join("\n").toLowerCase();
|
|
24
|
+
if (combined.includes("runway") || combined.includes("cash")) {
|
|
25
|
+
return { category: "runway", confidence: 0.74, evidence };
|
|
26
|
+
}
|
|
27
|
+
if (combined.includes("raise") || combined.includes("fund")) {
|
|
28
|
+
return { category: "fundraising", confidence: 0.72, evidence };
|
|
29
|
+
}
|
|
30
|
+
if (combined.includes("conflict")) {
|
|
31
|
+
return { category: "founder_conflict", confidence: 0.7, evidence };
|
|
32
|
+
}
|
|
33
|
+
if (combined.includes("pivot")) {
|
|
34
|
+
return { category: "pmf", confidence: 0.78, evidence };
|
|
35
|
+
}
|
|
36
|
+
return { category: "pmf", confidence: 0.68, evidence };
|
|
37
|
+
}
|
|
38
|
+
function coolingOffDate() {
|
|
39
|
+
return new Date(Date.now() + 24 * 60 * 60 * 1e3).toISOString();
|
|
40
|
+
}
|
|
41
|
+
function memorialDisclosureBody(request) {
|
|
42
|
+
return [
|
|
43
|
+
request.analysis.companyName,
|
|
44
|
+
request.analysis.narrative,
|
|
45
|
+
request.analysis.evidence.join("\n"),
|
|
46
|
+
request.lessons.map((lesson) => [lesson.title, lesson.lessonText, lesson.evidence.join("\n")].join("\n")).join("\n")
|
|
47
|
+
].join("\n");
|
|
48
|
+
}
|
|
49
|
+
var FounderCemetery = class _FounderCemetery {
|
|
50
|
+
#tenantId;
|
|
51
|
+
#debugRoot;
|
|
52
|
+
#contentStore;
|
|
53
|
+
#eventLog;
|
|
54
|
+
constructor(options) {
|
|
55
|
+
this.#tenantId = requireTenant(options.tenantId);
|
|
56
|
+
this.#debugRoot = options.debugRoot ?? process.cwd();
|
|
57
|
+
this.#contentStore = options.contentStore;
|
|
58
|
+
this.#eventLog = options.eventLog;
|
|
59
|
+
}
|
|
60
|
+
static async open(root = ".nebutra/founder-cemetery", options = {}) {
|
|
61
|
+
const tenantId = options.tenantId ?? "local";
|
|
62
|
+
await mkdir(root, { recursive: true });
|
|
63
|
+
const contentStore = await ContentStore.open(join(root, "content"), { tenantId });
|
|
64
|
+
const eventLog = await EventLog.open(join(root, "event-log"), { tenantId });
|
|
65
|
+
return new _FounderCemetery({ ...options, tenantId, contentStore, eventLog });
|
|
66
|
+
}
|
|
67
|
+
async startClosingFlow(request) {
|
|
68
|
+
const flow = {
|
|
69
|
+
companyId: request.companyId,
|
|
70
|
+
companyName: request.companyName,
|
|
71
|
+
recommendedMode: "pause",
|
|
72
|
+
availableModes: ["pause", "archive", "cemetery"],
|
|
73
|
+
requiresCoolingOff: true,
|
|
74
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
75
|
+
};
|
|
76
|
+
await this.#debug({ type: "start_closing_flow", tenantId: this.#tenantId, ...flow });
|
|
77
|
+
return flow;
|
|
78
|
+
}
|
|
79
|
+
async analyzeDeath(request) {
|
|
80
|
+
const evidence = request.timelineSummaries.length > 0 ? request.timelineSummaries : ["No timeline summaries were provided."];
|
|
81
|
+
const cause = inferCause(evidence);
|
|
82
|
+
const analysis = {
|
|
83
|
+
companyId: request.companyId,
|
|
84
|
+
companyName: request.companyName,
|
|
85
|
+
causes: [cause],
|
|
86
|
+
evidence,
|
|
87
|
+
narrative: `${request.companyName} appears to have stalled around ${cause.category}.`
|
|
88
|
+
};
|
|
89
|
+
await this.#debug({
|
|
90
|
+
type: "analyze_death",
|
|
91
|
+
tenantId: this.#tenantId,
|
|
92
|
+
companyId: request.companyId,
|
|
93
|
+
category: cause.category
|
|
94
|
+
});
|
|
95
|
+
return analysis;
|
|
96
|
+
}
|
|
97
|
+
async extractLessons(analysis) {
|
|
98
|
+
const title = analysis.causes[0]?.category === "runway" ? "Validate before scaling burn" : "Validate demand before widening the pitch";
|
|
99
|
+
const lesson = {
|
|
100
|
+
title,
|
|
101
|
+
lessonText: `${analysis.companyName} should preserve the decision context and avoid repeating the highest-impact ${analysis.causes[0]?.category ?? "pmf"} mistake.`,
|
|
102
|
+
evidence: analysis.evidence.slice(0, Math.max(2, analysis.evidence.length))
|
|
103
|
+
};
|
|
104
|
+
await this.#debug({
|
|
105
|
+
type: "extract_lessons",
|
|
106
|
+
tenantId: this.#tenantId,
|
|
107
|
+
companyId: analysis.companyId,
|
|
108
|
+
lessons: 1
|
|
109
|
+
});
|
|
110
|
+
return [lesson];
|
|
111
|
+
}
|
|
112
|
+
async publishMemorial(request) {
|
|
113
|
+
if (request.consentSignatures.length === 0) {
|
|
114
|
+
throw new CapabilityError("founder-cemetery", "Memorial publication requires consent", {
|
|
115
|
+
suggestion: "Collect founder consent signatures before publishing or keep the company paused.",
|
|
116
|
+
statusCode: 400
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
if (request.publishLevel !== "private") {
|
|
120
|
+
assertPublicDisclosureSafe({
|
|
121
|
+
capability: "founder-cemetery",
|
|
122
|
+
content: memorialDisclosureBody(request),
|
|
123
|
+
...request.redactions !== void 0 ? { redactions: request.redactions } : {},
|
|
124
|
+
suggestion: "Review detected private values and pass redactions before publishing."
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
const slug = slugify(request.analysis.companyName) || request.analysis.companyId;
|
|
128
|
+
const path = `cemetery/${slug}.json`;
|
|
129
|
+
const memorial = {
|
|
130
|
+
slug,
|
|
131
|
+
companyId: request.analysis.companyId,
|
|
132
|
+
companyName: request.analysis.companyName,
|
|
133
|
+
publishLevel: request.publishLevel,
|
|
134
|
+
coolingOffUntil: coolingOffDate(),
|
|
135
|
+
consentSignatures: request.consentSignatures,
|
|
136
|
+
redactions: request.redactions ?? [],
|
|
137
|
+
causes: request.analysis.causes,
|
|
138
|
+
lessons: request.lessons,
|
|
139
|
+
narrative: request.analysis.narrative
|
|
140
|
+
};
|
|
141
|
+
const snapshot = `${JSON.stringify(memorial, null, 2)}
|
|
142
|
+
`;
|
|
143
|
+
await this.#contentStore.write(path, snapshot);
|
|
144
|
+
const eventId = await this.#eventLog.commit({
|
|
145
|
+
traceId: assetId("founder_cemetery_publish", slug),
|
|
146
|
+
kind: "content_write",
|
|
147
|
+
affected: [path],
|
|
148
|
+
parent: null,
|
|
149
|
+
snapshot: { [path]: snapshot }
|
|
150
|
+
});
|
|
151
|
+
await this.#debug({
|
|
152
|
+
type: "publish_memorial",
|
|
153
|
+
tenantId: this.#tenantId,
|
|
154
|
+
companyId: request.analysis.companyId,
|
|
155
|
+
publishLevel: request.publishLevel
|
|
156
|
+
});
|
|
157
|
+
return {
|
|
158
|
+
slug,
|
|
159
|
+
path,
|
|
160
|
+
publishLevel: request.publishLevel,
|
|
161
|
+
coolingOffUntil: memorial.coolingOffUntil,
|
|
162
|
+
eventId,
|
|
163
|
+
lessons: request.lessons,
|
|
164
|
+
redactions: memorial.redactions
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
async doctor() {
|
|
168
|
+
const report = {
|
|
169
|
+
capability: "founder-cemetery",
|
|
170
|
+
ok: true,
|
|
171
|
+
checkedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
172
|
+
features: ["pause-first", "death-analysis", "lessons", "memorial", "cooling-off"],
|
|
173
|
+
suggestion: "Local memorial artifacts are active; global search and video recap remain lower-layer handoffs."
|
|
174
|
+
};
|
|
175
|
+
await this.#debug({ type: "doctor", tenantId: this.#tenantId });
|
|
176
|
+
return report;
|
|
177
|
+
}
|
|
178
|
+
async close() {
|
|
179
|
+
await this.#contentStore.close();
|
|
180
|
+
}
|
|
181
|
+
async #debug(entry) {
|
|
182
|
+
await appendCapabilityDebug("founder-cemetery", entry, { root: this.#debugRoot });
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
async function readFounderCemeteryDebug(root = process.cwd(), limit = 20) {
|
|
186
|
+
return readCapabilityDebug("founder-cemetery", { root, limit });
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export {
|
|
190
|
+
FounderCemetery,
|
|
191
|
+
readFounderCemeteryDebug
|
|
192
|
+
};
|
|
193
|
+
//# sourceMappingURL=chunk-X5WY4XBS.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { appendCapabilityDebug, readCapabilityDebug } from \"@nebutra/capability-kit/debug\";\nimport { ContentStore } from \"@nebutra/content-store\";\nimport { assertPublicDisclosureSafe } from \"@nebutra/ecosystem-safety\";\nimport { CapabilityError } from \"@nebutra/errors\";\nimport { EventLog } from \"@nebutra/event-log\";\nimport { assetId } from \"@nebutra/generation-context\";\n\nexport type CloseMode = \"pause\" | \"archive\" | \"cemetery\";\nexport type CauseCategory =\n | \"pmf\"\n | \"runway\"\n | \"fundraising\"\n | \"competition\"\n | \"founder_conflict\"\n | \"pivot\";\nexport type MemorialPublishLevel = \"private\" | \"community\" | \"public\";\n\nexport interface ClosingFlowRequest {\n readonly companyId: string;\n readonly companyName: string;\n readonly founderIds: readonly string[];\n}\n\nexport interface ClosingFlow {\n readonly companyId: string;\n readonly companyName: string;\n readonly recommendedMode: \"pause\";\n readonly availableModes: readonly CloseMode[];\n readonly requiresCoolingOff: true;\n readonly startedAt: string;\n}\n\nexport interface DeathAnalysisRequest {\n readonly companyId: string;\n readonly companyName: string;\n readonly timelineSummaries: readonly string[];\n}\n\nexport interface DeathCause {\n readonly category: CauseCategory;\n readonly confidence: number;\n readonly evidence: readonly string[];\n}\n\nexport interface DeathAnalysis {\n readonly companyId: string;\n readonly companyName: string;\n readonly causes: readonly DeathCause[];\n readonly narrative: string;\n readonly evidence: readonly string[];\n}\n\nexport interface Lesson {\n readonly title: string;\n readonly lessonText: string;\n readonly evidence: readonly string[];\n}\n\nexport interface PublishMemorialRequest {\n readonly analysis: DeathAnalysis;\n readonly lessons: readonly Lesson[];\n readonly publishLevel: MemorialPublishLevel;\n readonly consentSignatures: readonly string[];\n readonly redactions?: readonly string[];\n}\n\nexport interface Memorial {\n readonly slug: string;\n readonly path: string;\n readonly publishLevel: MemorialPublishLevel;\n readonly coolingOffUntil: string;\n readonly eventId: string;\n readonly lessons: readonly Lesson[];\n readonly redactions: readonly string[];\n}\n\nexport interface FounderCemeteryDoctorReport {\n readonly capability: \"founder-cemetery\";\n readonly ok: boolean;\n readonly checkedAt: string;\n readonly features: readonly string[];\n readonly suggestion?: string;\n}\n\nexport interface FounderCemeteryOptions {\n readonly tenantId?: string;\n readonly debugRoot?: string;\n readonly contentStore?: ContentStore;\n readonly eventLog?: EventLog;\n}\n\nfunction requireTenant(value: string | undefined): string {\n if (!value?.trim()) {\n throw new CapabilityError(\"founder-cemetery\", \"Founder Cemetery requires tenant context\", {\n suggestion: \"Pass tenantId so closure artifacts stay tenant-scoped.\",\n statusCode: 400,\n });\n }\n return value;\n}\n\nfunction slugify(value: string): string {\n return value\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .slice(0, 64);\n}\n\nfunction inferCause(evidence: readonly string[]): DeathCause {\n const combined = evidence.join(\"\\n\").toLowerCase();\n if (combined.includes(\"runway\") || combined.includes(\"cash\")) {\n return { category: \"runway\", confidence: 0.74, evidence };\n }\n if (combined.includes(\"raise\") || combined.includes(\"fund\")) {\n return { category: \"fundraising\", confidence: 0.72, evidence };\n }\n if (combined.includes(\"conflict\")) {\n return { category: \"founder_conflict\", confidence: 0.7, evidence };\n }\n if (combined.includes(\"pivot\")) {\n return { category: \"pmf\", confidence: 0.78, evidence };\n }\n return { category: \"pmf\", confidence: 0.68, evidence };\n}\n\nfunction coolingOffDate(): string {\n return new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString();\n}\n\nfunction memorialDisclosureBody(request: PublishMemorialRequest): string {\n return [\n request.analysis.companyName,\n request.analysis.narrative,\n request.analysis.evidence.join(\"\\n\"),\n request.lessons\n .map((lesson) => [lesson.title, lesson.lessonText, lesson.evidence.join(\"\\n\")].join(\"\\n\"))\n .join(\"\\n\"),\n ].join(\"\\n\");\n}\n\nexport class FounderCemetery {\n readonly #tenantId: string;\n readonly #debugRoot: string;\n readonly #contentStore: ContentStore;\n readonly #eventLog: EventLog;\n\n private constructor(\n options: Required<Pick<FounderCemeteryOptions, \"tenantId\" | \"contentStore\" | \"eventLog\">> &\n Pick<FounderCemeteryOptions, \"debugRoot\">,\n ) {\n this.#tenantId = requireTenant(options.tenantId);\n this.#debugRoot = options.debugRoot ?? process.cwd();\n this.#contentStore = options.contentStore;\n this.#eventLog = options.eventLog;\n }\n\n static async open(\n root = \".nebutra/founder-cemetery\",\n options: Omit<FounderCemeteryOptions, \"contentStore\" | \"eventLog\"> = {},\n ): Promise<FounderCemetery> {\n const tenantId = options.tenantId ?? \"local\";\n await mkdir(root, { recursive: true });\n const contentStore = await ContentStore.open(join(root, \"content\"), { tenantId });\n const eventLog = await EventLog.open(join(root, \"event-log\"), { tenantId });\n return new FounderCemetery({ ...options, tenantId, contentStore, eventLog });\n }\n\n async startClosingFlow(request: ClosingFlowRequest): Promise<ClosingFlow> {\n const flow: ClosingFlow = {\n companyId: request.companyId,\n companyName: request.companyName,\n recommendedMode: \"pause\",\n availableModes: [\"pause\", \"archive\", \"cemetery\"],\n requiresCoolingOff: true,\n startedAt: new Date().toISOString(),\n };\n await this.#debug({ type: \"start_closing_flow\", tenantId: this.#tenantId, ...flow });\n return flow;\n }\n\n async analyzeDeath(request: DeathAnalysisRequest): Promise<DeathAnalysis> {\n const evidence =\n request.timelineSummaries.length > 0\n ? request.timelineSummaries\n : [\"No timeline summaries were provided.\"];\n const cause = inferCause(evidence);\n const analysis: DeathAnalysis = {\n companyId: request.companyId,\n companyName: request.companyName,\n causes: [cause],\n evidence,\n narrative: `${request.companyName} appears to have stalled around ${cause.category}.`,\n };\n await this.#debug({\n type: \"analyze_death\",\n tenantId: this.#tenantId,\n companyId: request.companyId,\n category: cause.category,\n });\n return analysis;\n }\n\n async extractLessons(analysis: DeathAnalysis): Promise<readonly Lesson[]> {\n const title =\n analysis.causes[0]?.category === \"runway\"\n ? \"Validate before scaling burn\"\n : \"Validate demand before widening the pitch\";\n const lesson: Lesson = {\n title,\n lessonText: `${analysis.companyName} should preserve the decision context and avoid repeating the highest-impact ${analysis.causes[0]?.category ?? \"pmf\"} mistake.`,\n evidence: analysis.evidence.slice(0, Math.max(2, analysis.evidence.length)),\n };\n await this.#debug({\n type: \"extract_lessons\",\n tenantId: this.#tenantId,\n companyId: analysis.companyId,\n lessons: 1,\n });\n return [lesson];\n }\n\n async publishMemorial(request: PublishMemorialRequest): Promise<Memorial> {\n if (request.consentSignatures.length === 0) {\n throw new CapabilityError(\"founder-cemetery\", \"Memorial publication requires consent\", {\n suggestion:\n \"Collect founder consent signatures before publishing or keep the company paused.\",\n statusCode: 400,\n });\n }\n if (request.publishLevel !== \"private\") {\n assertPublicDisclosureSafe({\n capability: \"founder-cemetery\",\n content: memorialDisclosureBody(request),\n ...(request.redactions !== undefined ? { redactions: request.redactions } : {}),\n suggestion: \"Review detected private values and pass redactions before publishing.\",\n });\n }\n\n const slug = slugify(request.analysis.companyName) || request.analysis.companyId;\n const path = `cemetery/${slug}.json`;\n const memorial = {\n slug,\n companyId: request.analysis.companyId,\n companyName: request.analysis.companyName,\n publishLevel: request.publishLevel,\n coolingOffUntil: coolingOffDate(),\n consentSignatures: request.consentSignatures,\n redactions: request.redactions ?? [],\n causes: request.analysis.causes,\n lessons: request.lessons,\n narrative: request.analysis.narrative,\n };\n const snapshot = `${JSON.stringify(memorial, null, 2)}\\n`;\n await this.#contentStore.write(path, snapshot);\n const eventId = await this.#eventLog.commit({\n traceId: assetId(\"founder_cemetery_publish\", slug),\n kind: \"content_write\",\n affected: [path],\n parent: null,\n snapshot: { [path]: snapshot },\n });\n await this.#debug({\n type: \"publish_memorial\",\n tenantId: this.#tenantId,\n companyId: request.analysis.companyId,\n publishLevel: request.publishLevel,\n });\n return {\n slug,\n path,\n publishLevel: request.publishLevel,\n coolingOffUntil: memorial.coolingOffUntil,\n eventId,\n lessons: request.lessons,\n redactions: memorial.redactions,\n };\n }\n\n async doctor(): Promise<FounderCemeteryDoctorReport> {\n const report: FounderCemeteryDoctorReport = {\n capability: \"founder-cemetery\",\n ok: true,\n checkedAt: new Date().toISOString(),\n features: [\"pause-first\", \"death-analysis\", \"lessons\", \"memorial\", \"cooling-off\"],\n suggestion:\n \"Local memorial artifacts are active; global search and video recap remain lower-layer handoffs.\",\n };\n await this.#debug({ type: \"doctor\", tenantId: this.#tenantId });\n return report;\n }\n\n async close(): Promise<void> {\n await this.#contentStore.close();\n }\n\n async #debug(entry: Record<string, unknown>): Promise<void> {\n await appendCapabilityDebug(\"founder-cemetery\", entry, { root: this.#debugRoot });\n }\n}\n\nexport async function readFounderCemeteryDebug(\n root = process.cwd(),\n limit = 20,\n): Promise<unknown[]> {\n return readCapabilityDebug(\"founder-cemetery\", { root, limit });\n}\n"],"mappings":"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","names":[]}
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import {
|
|
2
|
+
FounderCemetery,
|
|
3
|
+
readFounderCemeteryDebug
|
|
4
|
+
} from "./chunk-X5WY4XBS.js";
|
|
5
|
+
|
|
6
|
+
// src/cli.ts
|
|
7
|
+
var command = process.argv[2] ?? "doctor";
|
|
8
|
+
var root = process.env.FOUNDER_CEMETERY_ROOT ?? ".nebutra/founder-cemetery";
|
|
9
|
+
var tenantId = process.env.NEBUTRA_TENANT_ID ?? "local";
|
|
10
|
+
if (command === "doctor") {
|
|
11
|
+
const cemetery = await FounderCemetery.open(root, { tenantId });
|
|
12
|
+
try {
|
|
13
|
+
process.stdout.write(`${JSON.stringify(await cemetery.doctor(), null, 2)}
|
|
14
|
+
`);
|
|
15
|
+
} finally {
|
|
16
|
+
await cemetery.close();
|
|
17
|
+
}
|
|
18
|
+
} else if (command === "quickstart") {
|
|
19
|
+
const cemetery = await FounderCemetery.open(root, { tenantId });
|
|
20
|
+
try {
|
|
21
|
+
const flow = await cemetery.startClosingFlow({
|
|
22
|
+
companyId: "loop",
|
|
23
|
+
companyName: "Loop",
|
|
24
|
+
founderIds: ["alice"]
|
|
25
|
+
});
|
|
26
|
+
process.stdout.write(`${JSON.stringify(flow, null, 2)}
|
|
27
|
+
`);
|
|
28
|
+
} finally {
|
|
29
|
+
await cemetery.close();
|
|
30
|
+
}
|
|
31
|
+
} else if (command === "debug") {
|
|
32
|
+
process.stdout.write(
|
|
33
|
+
`${JSON.stringify({ capability: "founder-cemetery", entries: await readFounderCemeteryDebug() }, null, 2)}
|
|
34
|
+
`
|
|
35
|
+
);
|
|
36
|
+
} else {
|
|
37
|
+
process.stderr.write(`Unknown founder-cemetery command: ${command}
|
|
38
|
+
`);
|
|
39
|
+
process.exitCode = 1;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts"],"sourcesContent":["import { FounderCemetery, readFounderCemeteryDebug } from \"./index\";\n\nconst command = process.argv[2] ?? \"doctor\";\nconst root = process.env.FOUNDER_CEMETERY_ROOT ?? \".nebutra/founder-cemetery\";\nconst tenantId = process.env.NEBUTRA_TENANT_ID ?? \"local\";\n\nif (command === \"doctor\") {\n const cemetery = await FounderCemetery.open(root, { tenantId });\n try {\n process.stdout.write(`${JSON.stringify(await cemetery.doctor(), null, 2)}\\n`);\n } finally {\n await cemetery.close();\n }\n} else if (command === \"quickstart\") {\n const cemetery = await FounderCemetery.open(root, { tenantId });\n try {\n const flow = await cemetery.startClosingFlow({\n companyId: \"loop\",\n companyName: \"Loop\",\n founderIds: [\"alice\"],\n });\n process.stdout.write(`${JSON.stringify(flow, null, 2)}\\n`);\n } finally {\n await cemetery.close();\n }\n} else if (command === \"debug\") {\n process.stdout.write(\n `${JSON.stringify({ capability: \"founder-cemetery\", entries: await readFounderCemeteryDebug() }, null, 2)}\\n`,\n );\n} else {\n process.stderr.write(`Unknown founder-cemetery command: ${command}\\n`);\n process.exitCode = 1;\n}\n"],"mappings":";;;;;;AAEA,IAAM,UAAU,QAAQ,KAAK,CAAC,KAAK;AACnC,IAAM,OAAO,QAAQ,IAAI,yBAAyB;AAClD,IAAM,WAAW,QAAQ,IAAI,qBAAqB;AAElD,IAAI,YAAY,UAAU;AACxB,QAAM,WAAW,MAAM,gBAAgB,KAAK,MAAM,EAAE,SAAS,CAAC;AAC9D,MAAI;AACF,YAAQ,OAAO,MAAM,GAAG,KAAK,UAAU,MAAM,SAAS,OAAO,GAAG,MAAM,CAAC,CAAC;AAAA,CAAI;AAAA,EAC9E,UAAE;AACA,UAAM,SAAS,MAAM;AAAA,EACvB;AACF,WAAW,YAAY,cAAc;AACnC,QAAM,WAAW,MAAM,gBAAgB,KAAK,MAAM,EAAE,SAAS,CAAC;AAC9D,MAAI;AACF,UAAM,OAAO,MAAM,SAAS,iBAAiB;AAAA,MAC3C,WAAW;AAAA,MACX,aAAa;AAAA,MACb,YAAY,CAAC,OAAO;AAAA,IACtB,CAAC;AACD,YAAQ,OAAO,MAAM,GAAG,KAAK,UAAU,MAAM,MAAM,CAAC,CAAC;AAAA,CAAI;AAAA,EAC3D,UAAE;AACA,UAAM,SAAS,MAAM;AAAA,EACvB;AACF,WAAW,YAAY,SAAS;AAC9B,UAAQ,OAAO;AAAA,IACb,GAAG,KAAK,UAAU,EAAE,YAAY,oBAAoB,SAAS,MAAM,yBAAyB,EAAE,GAAG,MAAM,CAAC,CAAC;AAAA;AAAA,EAC3G;AACF,OAAO;AACL,UAAQ,OAAO,MAAM,qCAAqC,OAAO;AAAA,CAAI;AACrE,UAAQ,WAAW;AACrB;","names":[]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { ContentStore } from '@nebutra/content-store';
|
|
2
|
+
import { EventLog } from '@nebutra/event-log';
|
|
3
|
+
|
|
4
|
+
type CloseMode = "pause" | "archive" | "cemetery";
|
|
5
|
+
type CauseCategory = "pmf" | "runway" | "fundraising" | "competition" | "founder_conflict" | "pivot";
|
|
6
|
+
type MemorialPublishLevel = "private" | "community" | "public";
|
|
7
|
+
interface ClosingFlowRequest {
|
|
8
|
+
readonly companyId: string;
|
|
9
|
+
readonly companyName: string;
|
|
10
|
+
readonly founderIds: readonly string[];
|
|
11
|
+
}
|
|
12
|
+
interface ClosingFlow {
|
|
13
|
+
readonly companyId: string;
|
|
14
|
+
readonly companyName: string;
|
|
15
|
+
readonly recommendedMode: "pause";
|
|
16
|
+
readonly availableModes: readonly CloseMode[];
|
|
17
|
+
readonly requiresCoolingOff: true;
|
|
18
|
+
readonly startedAt: string;
|
|
19
|
+
}
|
|
20
|
+
interface DeathAnalysisRequest {
|
|
21
|
+
readonly companyId: string;
|
|
22
|
+
readonly companyName: string;
|
|
23
|
+
readonly timelineSummaries: readonly string[];
|
|
24
|
+
}
|
|
25
|
+
interface DeathCause {
|
|
26
|
+
readonly category: CauseCategory;
|
|
27
|
+
readonly confidence: number;
|
|
28
|
+
readonly evidence: readonly string[];
|
|
29
|
+
}
|
|
30
|
+
interface DeathAnalysis {
|
|
31
|
+
readonly companyId: string;
|
|
32
|
+
readonly companyName: string;
|
|
33
|
+
readonly causes: readonly DeathCause[];
|
|
34
|
+
readonly narrative: string;
|
|
35
|
+
readonly evidence: readonly string[];
|
|
36
|
+
}
|
|
37
|
+
interface Lesson {
|
|
38
|
+
readonly title: string;
|
|
39
|
+
readonly lessonText: string;
|
|
40
|
+
readonly evidence: readonly string[];
|
|
41
|
+
}
|
|
42
|
+
interface PublishMemorialRequest {
|
|
43
|
+
readonly analysis: DeathAnalysis;
|
|
44
|
+
readonly lessons: readonly Lesson[];
|
|
45
|
+
readonly publishLevel: MemorialPublishLevel;
|
|
46
|
+
readonly consentSignatures: readonly string[];
|
|
47
|
+
readonly redactions?: readonly string[];
|
|
48
|
+
}
|
|
49
|
+
interface Memorial {
|
|
50
|
+
readonly slug: string;
|
|
51
|
+
readonly path: string;
|
|
52
|
+
readonly publishLevel: MemorialPublishLevel;
|
|
53
|
+
readonly coolingOffUntil: string;
|
|
54
|
+
readonly eventId: string;
|
|
55
|
+
readonly lessons: readonly Lesson[];
|
|
56
|
+
readonly redactions: readonly string[];
|
|
57
|
+
}
|
|
58
|
+
interface FounderCemeteryDoctorReport {
|
|
59
|
+
readonly capability: "founder-cemetery";
|
|
60
|
+
readonly ok: boolean;
|
|
61
|
+
readonly checkedAt: string;
|
|
62
|
+
readonly features: readonly string[];
|
|
63
|
+
readonly suggestion?: string;
|
|
64
|
+
}
|
|
65
|
+
interface FounderCemeteryOptions {
|
|
66
|
+
readonly tenantId?: string;
|
|
67
|
+
readonly debugRoot?: string;
|
|
68
|
+
readonly contentStore?: ContentStore;
|
|
69
|
+
readonly eventLog?: EventLog;
|
|
70
|
+
}
|
|
71
|
+
declare class FounderCemetery {
|
|
72
|
+
#private;
|
|
73
|
+
private constructor();
|
|
74
|
+
static open(root?: string, options?: Omit<FounderCemeteryOptions, "contentStore" | "eventLog">): Promise<FounderCemetery>;
|
|
75
|
+
startClosingFlow(request: ClosingFlowRequest): Promise<ClosingFlow>;
|
|
76
|
+
analyzeDeath(request: DeathAnalysisRequest): Promise<DeathAnalysis>;
|
|
77
|
+
extractLessons(analysis: DeathAnalysis): Promise<readonly Lesson[]>;
|
|
78
|
+
publishMemorial(request: PublishMemorialRequest): Promise<Memorial>;
|
|
79
|
+
doctor(): Promise<FounderCemeteryDoctorReport>;
|
|
80
|
+
close(): Promise<void>;
|
|
81
|
+
}
|
|
82
|
+
declare function readFounderCemeteryDebug(root?: string, limit?: number): Promise<unknown[]>;
|
|
83
|
+
|
|
84
|
+
export { type CauseCategory, type CloseMode, type ClosingFlow, type ClosingFlowRequest, type DeathAnalysis, type DeathAnalysisRequest, type DeathCause, FounderCemetery, type FounderCemeteryDoctorReport, type FounderCemeteryOptions, type Lesson, type Memorial, type MemorialPublishLevel, type PublishMemorialRequest, readFounderCemeteryDebug };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { FounderCemetery } from "../src/index";
|
|
2
|
+
|
|
3
|
+
const cemetery = await FounderCemetery.open(".nebutra/founder-cemetery-example", {
|
|
4
|
+
tenantId: "local",
|
|
5
|
+
});
|
|
6
|
+
|
|
7
|
+
try {
|
|
8
|
+
process.stdout.write(`${JSON.stringify(await cemetery.doctor(), null, 2)}\n`);
|
|
9
|
+
} finally {
|
|
10
|
+
await cemetery.close();
|
|
11
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { FounderCemetery } from "../src/index";
|
|
2
|
+
|
|
3
|
+
const cemetery = await FounderCemetery.open(".nebutra/founder-cemetery-memorial-example", {
|
|
4
|
+
tenantId: "local",
|
|
5
|
+
});
|
|
6
|
+
|
|
7
|
+
try {
|
|
8
|
+
const analysis = await cemetery.analyzeDeath({
|
|
9
|
+
companyId: "loop",
|
|
10
|
+
companyName: "Loop",
|
|
11
|
+
timelineSummaries: ["Pivoted twice before validating customer demand", "Outbound stayed flat"],
|
|
12
|
+
});
|
|
13
|
+
const lessons = await cemetery.extractLessons(analysis);
|
|
14
|
+
process.stdout.write(
|
|
15
|
+
`${JSON.stringify(await cemetery.publishMemorial({ analysis, lessons, publishLevel: "community", consentSignatures: ["alice"] }), null, 2)}\n`,
|
|
16
|
+
);
|
|
17
|
+
} finally {
|
|
18
|
+
await cemetery.close();
|
|
19
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { FounderCemetery } from "../src/index";
|
|
2
|
+
|
|
3
|
+
const cemetery = await FounderCemetery.open(".nebutra/founder-cemetery-example", {
|
|
4
|
+
tenantId: "local",
|
|
5
|
+
});
|
|
6
|
+
|
|
7
|
+
try {
|
|
8
|
+
const flow = await cemetery.startClosingFlow({
|
|
9
|
+
companyId: "loop",
|
|
10
|
+
companyName: "Loop",
|
|
11
|
+
founderIds: ["alice"],
|
|
12
|
+
});
|
|
13
|
+
process.stdout.write(`${JSON.stringify(flow, null, 2)}\n`);
|
|
14
|
+
} finally {
|
|
15
|
+
await cemetery.close();
|
|
16
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nebutra/founder-cemetery",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Company closing, postmortem, lesson extraction, and memorial publication surface",
|
|
5
|
+
"private": false,
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"nebutra": {
|
|
9
|
+
"status": "wip",
|
|
10
|
+
"productionReady": false,
|
|
11
|
+
"surface": "ecosystem-product",
|
|
12
|
+
"requires": [
|
|
13
|
+
"@nebutra/content-store for memorial artifacts",
|
|
14
|
+
"@nebutra/event-log for closure checkpoints",
|
|
15
|
+
"@nebutra/ecosystem-safety for public-disclosure PII and secret checks",
|
|
16
|
+
"@nebutra/capability-kit for debug and doctor surfaces"
|
|
17
|
+
],
|
|
18
|
+
"gaps": [
|
|
19
|
+
"Memorial video output is represented as a handoff manifest until video composition is wired",
|
|
20
|
+
"Multi-founder legal signing is represented as explicit consent signatures",
|
|
21
|
+
"Global pattern matching remains local until the ecosystem KB is online"
|
|
22
|
+
],
|
|
23
|
+
"featureId": "founder-cemetery",
|
|
24
|
+
"category": "ai",
|
|
25
|
+
"summary": "Ethical close-company flow and evidence-backed memorial product surface"
|
|
26
|
+
},
|
|
27
|
+
"main": "./src/index.ts",
|
|
28
|
+
"types": "./src/index.ts",
|
|
29
|
+
"exports": {
|
|
30
|
+
".": "./src/index.ts"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"@nebutra/capability-kit": "0.2.0",
|
|
34
|
+
"@nebutra/content-store": "0.1.0",
|
|
35
|
+
"@nebutra/ecosystem-safety": "0.1.0",
|
|
36
|
+
"@nebutra/errors": "0.1.0",
|
|
37
|
+
"@nebutra/event-log": "0.1.0",
|
|
38
|
+
"@nebutra/generation-context": "0.1.0"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@types/node": "^22.19.15",
|
|
42
|
+
"tsup": "^8.5.1",
|
|
43
|
+
"tsx": "^4.21.0",
|
|
44
|
+
"typescript": "^5.9.3",
|
|
45
|
+
"vitest": "^4.1.4"
|
|
46
|
+
},
|
|
47
|
+
"homepage": "https://github.com/Nebutra/Nebutra-Sailor/tree/main/packages/ai/founder-cemetery#readme",
|
|
48
|
+
"repository": {
|
|
49
|
+
"type": "git",
|
|
50
|
+
"url": "git+https://github.com/Nebutra/Nebutra-Sailor.git",
|
|
51
|
+
"directory": "packages/ai/founder-cemetery"
|
|
52
|
+
},
|
|
53
|
+
"bugs": {
|
|
54
|
+
"url": "https://github.com/Nebutra/Nebutra-Sailor/issues"
|
|
55
|
+
},
|
|
56
|
+
"publishConfig": {
|
|
57
|
+
"access": "public"
|
|
58
|
+
},
|
|
59
|
+
"scripts": {
|
|
60
|
+
"build": "tsup",
|
|
61
|
+
"test": "vitest run",
|
|
62
|
+
"typecheck": "tsc --noEmit"
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: close_company
|
|
3
|
+
kind: play
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
description: Guide a founder through pause, archive, or evidence-backed memorial publishing
|
|
6
|
+
required_skills:
|
|
7
|
+
- content_store.write
|
|
8
|
+
- event_log.commit
|
|
9
|
+
sub_agents:
|
|
10
|
+
- role: postmortem_curator
|
|
11
|
+
allowed_skills: [content_store.write]
|
|
12
|
+
depends_on_plays: []
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## What this play does
|
|
16
|
+
|
|
17
|
+
Starts with a reversible pause recommendation, then helps the founder decide whether to archive or publish a memorial.
|
|
18
|
+
|
|
19
|
+
## Boundaries
|
|
20
|
+
|
|
21
|
+
- There is no one-click delete.
|
|
22
|
+
- Public memorials need consent and a cooling-off period.
|
|
23
|
+
- Lessons must link back to evidence from the company timeline.
|
package/src/cli.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { FounderCemetery, readFounderCemeteryDebug } from "./index";
|
|
2
|
+
|
|
3
|
+
const command = process.argv[2] ?? "doctor";
|
|
4
|
+
const root = process.env.FOUNDER_CEMETERY_ROOT ?? ".nebutra/founder-cemetery";
|
|
5
|
+
const tenantId = process.env.NEBUTRA_TENANT_ID ?? "local";
|
|
6
|
+
|
|
7
|
+
if (command === "doctor") {
|
|
8
|
+
const cemetery = await FounderCemetery.open(root, { tenantId });
|
|
9
|
+
try {
|
|
10
|
+
process.stdout.write(`${JSON.stringify(await cemetery.doctor(), null, 2)}\n`);
|
|
11
|
+
} finally {
|
|
12
|
+
await cemetery.close();
|
|
13
|
+
}
|
|
14
|
+
} else if (command === "quickstart") {
|
|
15
|
+
const cemetery = await FounderCemetery.open(root, { tenantId });
|
|
16
|
+
try {
|
|
17
|
+
const flow = await cemetery.startClosingFlow({
|
|
18
|
+
companyId: "loop",
|
|
19
|
+
companyName: "Loop",
|
|
20
|
+
founderIds: ["alice"],
|
|
21
|
+
});
|
|
22
|
+
process.stdout.write(`${JSON.stringify(flow, null, 2)}\n`);
|
|
23
|
+
} finally {
|
|
24
|
+
await cemetery.close();
|
|
25
|
+
}
|
|
26
|
+
} else if (command === "debug") {
|
|
27
|
+
process.stdout.write(
|
|
28
|
+
`${JSON.stringify({ capability: "founder-cemetery", entries: await readFounderCemeteryDebug() }, null, 2)}\n`,
|
|
29
|
+
);
|
|
30
|
+
} else {
|
|
31
|
+
process.stderr.write(`Unknown founder-cemetery command: ${command}\n`);
|
|
32
|
+
process.exitCode = 1;
|
|
33
|
+
}
|