@nebutra/founder-cemetery 0.1.2 → 0.1.4

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.
@@ -9,7 +9,7 @@ import { CapabilityError } from "@nebutra/errors";
9
9
  import { EventLog } from "@nebutra/event-log";
10
10
  import { assetId } from "@nebutra/generation-context";
11
11
  function slugify(value) {
12
- return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64);
12
+ return value.slice(0, 200).toLowerCase().replace(/[^a-z0-9]{1,200}/g, "-").replace(/^-{1,200}|-{1,200}$/g, "").slice(0, 64);
13
13
  }
14
14
  function inferCause(evidence) {
15
15
  const combined = evidence.join("\n").toLowerCase();
@@ -188,4 +188,4 @@ export {
188
188
  FounderCemetery,
189
189
  readFounderCemeteryDebug
190
190
  };
191
- //# sourceMappingURL=chunk-EJUWG7L2.js.map
191
+ //# sourceMappingURL=chunk-NUTC3QQ4.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 { requireCapabilityTenant } from \"@nebutra/capability-kit\";\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 slugify(value: string): string {\n return value\n .slice(0, 200)\n .toLowerCase()\n .replace(/[^a-z0-9]{1,200}/g, \"-\")\n .replace(/^-{1,200}|-{1,200}$/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 = requireCapabilityTenant({\n explicit: options.tenantId,\n onMissing: () =>\n 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 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.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  FounderCemetery,
3
3
  readFounderCemeteryDebug
4
- } from "./chunk-EJUWG7L2.js";
4
+ } from "./chunk-NUTC3QQ4.js";
5
5
 
6
6
  // src/cli.ts
7
7
  var command = process.argv[2] ?? "doctor";
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  FounderCemetery,
3
3
  readFounderCemeteryDebug
4
- } from "./chunk-EJUWG7L2.js";
4
+ } from "./chunk-NUTC3QQ4.js";
5
5
  export {
6
6
  FounderCemetery,
7
7
  readFounderCemeteryDebug
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nebutra/founder-cemetery",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "Company closing, postmortem, lesson extraction, and memorial publication surface",
5
5
  "private": false,
6
6
  "license": "MIT",
@@ -24,21 +24,25 @@
24
24
  "category": "ai",
25
25
  "summary": "Ethical close-company flow and evidence-backed memorial product surface"
26
26
  },
27
- "main": "./src/index.ts",
28
- "types": "./src/index.ts",
27
+ "main": "./dist/index.js",
28
+ "types": "./dist/index.d.ts",
29
29
  "exports": {
30
- ".": "./src/index.ts"
30
+ ".": {
31
+ "types": "./dist/index.d.ts",
32
+ "import": "./dist/index.js",
33
+ "default": "./dist/index.js"
34
+ }
31
35
  },
32
36
  "dependencies": {
33
- "@nebutra/capability-kit": "0.2.1",
34
- "@nebutra/content-store": "0.1.1",
35
- "@nebutra/ecosystem-safety": "0.1.1",
36
- "@nebutra/errors": "0.1.1",
37
- "@nebutra/event-log": "0.1.1",
38
- "@nebutra/generation-context": "0.1.1"
37
+ "@nebutra/capability-kit": "0.2.4",
38
+ "@nebutra/ecosystem-safety": "0.1.3",
39
+ "@nebutra/errors": "0.1.2",
40
+ "@nebutra/generation-context": "0.1.3",
41
+ "@nebutra/event-log": "0.1.4",
42
+ "@nebutra/content-store": "0.1.4"
39
43
  },
40
44
  "devDependencies": {
41
- "@types/node": "^22.19.15",
45
+ "@types/node": "^25.9.1",
42
46
  "tsup": "^8.5.1",
43
47
  "tsx": "^4.21.0",
44
48
  "typescript": "^5.9.3",
@@ -56,6 +60,12 @@
56
60
  "publishConfig": {
57
61
  "access": "public"
58
62
  },
63
+ "files": [
64
+ "dist",
65
+ "README.md",
66
+ "LICENSE",
67
+ "CHANGELOG.md"
68
+ ],
59
69
  "scripts": {
60
70
  "build": "tsup",
61
71
  "test": "vitest run",
@@ -1,5 +0,0 @@
1
- {"at":"2026-05-19T08:15:21.765Z","type":"reindex","tenantId":"tenant_a","files":0}
2
- {"at":"2026-05-19T08:15:21.883Z","type":"reindex","tenantId":"tenant_a","files":0}
3
- {"at":"2026-05-19T08:15:21.927Z","type":"write","tenantId":"tenant_a","path":"cemetery/loop.json"}
4
- {"at":"2026-05-19T08:15:22.029Z","type":"reindex","tenantId":"tenant_a","files":0}
5
- {"at":"2026-05-19T08:15:22.081Z","type":"reindex","tenantId":"tenant_a","files":0}
@@ -1 +0,0 @@
1
- {"at":"2026-05-19T08:15:21.956Z","traceId":"founder_cemetery_publish_loop_mpccydla","kind":"content_write","affected":["cemetery/loop.json"],"parent":null,"snapshot":{"cemetery/loop.json":"{\n \"slug\": \"loop\",\n \"companyId\": \"loop\",\n \"companyName\": \"Loop\",\n \"publishLevel\": \"community\",\n \"coolingOffUntil\": \"2026-05-20T08:15:21.897Z\",\n \"consentSignatures\": [\n \"alice\"\n ],\n \"redactions\": [],\n \"causes\": [\n {\n \"category\": \"pmf\",\n \"confidence\": 0.78,\n \"evidence\": [\n \"Pivoted from devtools to sales without user interviews\",\n \"Outbound reply rate stayed below 1 percent\"\n ]\n }\n ],\n \"lessons\": [\n {\n \"title\": \"Validate demand before widening the pitch\",\n \"lessonText\": \"Loop should preserve the decision context and avoid repeating the highest-impact pmf mistake.\",\n \"evidence\": [\n \"Pivoted from devtools to sales without user interviews\",\n \"Outbound reply rate stayed below 1 percent\"\n ]\n }\n ],\n \"narrative\": \"Loop appears to have stalled around pmf.\"\n}\n"},"id":"88d85c40ba4529577b9a10d16fafef8d5e5cbc5081dba3e0f08cb7d8fa8c7e8e","tenantId":"tenant_a","summary":"content_write touched 1 path(s)","objectHashes":["ffe8f001f3b66d02a4aeaedc34494a0babde2e9ed368295ac8a0befe996a594e"]}
@@ -1,8 +0,0 @@
1
- {"at":"2026-05-19T08:15:21.773Z","type":"start_closing_flow","tenantId":"tenant_a","companyId":"loop","companyName":"Loop","recommendedMode":"pause","availableModes":["pause","archive","cemetery"],"requiresCoolingOff":true,"startedAt":"2026-05-19T08:15:21.769Z"}
2
- {"at":"2026-05-19T08:15:21.889Z","type":"analyze_death","tenantId":"tenant_a","companyId":"loop","category":"pmf"}
3
- {"at":"2026-05-19T08:15:21.896Z","type":"extract_lessons","tenantId":"tenant_a","companyId":"loop","lessons":1}
4
- {"at":"2026-05-19T08:15:21.969Z","type":"publish_memorial","tenantId":"tenant_a","companyId":"loop","publishLevel":"community"}
5
- {"at":"2026-05-19T08:15:22.033Z","type":"analyze_death","tenantId":"tenant_a","companyId":"loop","category":"runway"}
6
- {"at":"2026-05-19T08:15:22.033Z","type":"extract_lessons","tenantId":"tenant_a","companyId":"loop","lessons":1}
7
- {"at":"2026-05-19T08:15:22.082Z","type":"analyze_death","tenantId":"tenant_a","companyId":"loop","category":"pmf"}
8
- {"at":"2026-05-19T08:15:22.082Z","type":"extract_lessons","tenantId":"tenant_a","companyId":"loop","lessons":1}
@@ -1,22 +0,0 @@
1
-
2
- > @nebutra/founder-cemetery@0.1.2 build /home/runner/work/Nebutra-Sailor/Nebutra-Sailor/packages/ai/founder-cemetery
3
- > tsup
4
-
5
- CLI Building entry: src/cli.ts, src/index.ts
6
- CLI Using tsconfig: tsconfig.json
7
- CLI tsup v8.5.1
8
- CLI Using tsup config: /home/runner/work/Nebutra-Sailor/Nebutra-Sailor/packages/ai/founder-cemetery/tsup.config.ts
9
- CLI Target: es2022
10
- CLI Cleaning output folder
11
- ESM Build start
12
- ESM dist/cli.js 1.16 KB
13
- ESM dist/index.js 176.00 B
14
- ESM dist/chunk-EJUWG7L2.js 7.08 KB
15
- ESM dist/cli.js.map 2.06 KB
16
- ESM dist/index.js.map 71.00 B
17
- ESM dist/chunk-EJUWG7L2.js.map 15.00 KB
18
- ESM ⚡️ Build success in 92ms
19
- DTS Build start
20
- DTS ⚡️ Build success in 14372ms
21
- DTS dist/cli.d.ts 13.00 B
22
- DTS dist/index.d.ts 3.22 KB
@@ -1,15 +0,0 @@
1
-
2
- > @nebutra/founder-cemetery@0.1.2 test /home/runner/work/Nebutra-Sailor/Nebutra-Sailor/packages/ai/founder-cemetery
3
- > vitest run
4
-
5
-
6
-  RUN  v4.1.4 /home/runner/work/Nebutra-Sailor/Nebutra-Sailor/packages/ai/founder-cemetery
7
-
8
- ✓ src/index.test.ts (4 tests) 618ms
9
- ✓ starts with pause as the safe default instead of one-click deletion  328ms
10
-
11
-  Test Files  1 passed (1)
12
-  Tests  4 passed (4)
13
-  Start at  08:15:19
14
-  Duration  2.45s (transform 783ms, setup 0ms, import 994ms, tests 618ms, environment 0ms)
15
-
@@ -1,4 +0,0 @@
1
-
2
- > @nebutra/founder-cemetery@0.1.2 typecheck /home/runner/work/Nebutra-Sailor/Nebutra-Sailor/packages/ai/founder-cemetery
3
- > tsc --noEmit
4
-
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { requireCapabilityTenant } from \"@nebutra/capability-kit\";\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 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 = requireCapabilityTenant({\n explicit: options.tenantId,\n onMissing: () =>\n 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 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":[]}
@@ -1,11 +0,0 @@
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
- }
@@ -1,19 +0,0 @@
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
- }
@@ -1,16 +0,0 @@
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
- }
@@ -1,23 +0,0 @@
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 DELETED
@@ -1,33 +0,0 @@
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
- }
package/src/index.test.ts DELETED
@@ -1,104 +0,0 @@
1
- import { mkdtemp, rm } from "node:fs/promises";
2
- import { tmpdir } from "node:os";
3
- import { join } from "node:path";
4
- import { afterEach, describe, expect, it } from "vitest";
5
- import { FounderCemetery, readFounderCemeteryDebug } from "./index";
6
-
7
- let root: string | undefined;
8
- let cemetery: FounderCemetery | undefined;
9
-
10
- afterEach(async () => {
11
- if (cemetery) await cemetery.close();
12
- if (root) await rm(root, { recursive: true, force: true });
13
- root = undefined;
14
- cemetery = undefined;
15
- });
16
-
17
- async function open(): Promise<FounderCemetery> {
18
- root = await mkdtemp(join(tmpdir(), "founder-cemetery-"));
19
- cemetery = await FounderCemetery.open(root, { tenantId: "tenant_a" });
20
- return cemetery;
21
- }
22
-
23
- describe("founder-cemetery", () => {
24
- it("starts with pause as the safe default instead of one-click deletion", async () => {
25
- const runtime = await open();
26
-
27
- const flow = await runtime.startClosingFlow({
28
- companyId: "loop",
29
- companyName: "Loop",
30
- founderIds: ["alice"],
31
- });
32
-
33
- expect(flow.recommendedMode).toBe("pause");
34
- expect(flow.availableModes).toEqual(["pause", "archive", "cemetery"]);
35
- expect(flow.requiresCoolingOff).toBe(true);
36
- });
37
-
38
- it("extracts evidence-backed lessons and publishes only with consent", async () => {
39
- const runtime = await open();
40
- const analysis = await runtime.analyzeDeath({
41
- companyId: "loop",
42
- companyName: "Loop",
43
- timelineSummaries: [
44
- "Pivoted from devtools to sales without user interviews",
45
- "Outbound reply rate stayed below 1 percent",
46
- ],
47
- });
48
- const lessons = await runtime.extractLessons(analysis);
49
- const memorial = await runtime.publishMemorial({
50
- analysis,
51
- lessons,
52
- publishLevel: "community",
53
- consentSignatures: ["alice"],
54
- });
55
-
56
- expect(analysis.causes[0]?.category).toBe("pmf");
57
- expect(lessons[0]?.evidence).toHaveLength(2);
58
- expect(memorial.path).toBe(`cemetery/${memorial.slug}.json`);
59
- expect(memorial.coolingOffUntil).toEqual(expect.any(String));
60
- });
61
-
62
- it("refuses public memorials without explicit consent", async () => {
63
- const runtime = await open();
64
- const analysis = await runtime.analyzeDeath({
65
- companyId: "loop",
66
- companyName: "Loop",
67
- timelineSummaries: ["Ran out of runway after failed raise"],
68
- });
69
-
70
- await expect(
71
- runtime.publishMemorial({
72
- analysis,
73
- lessons: await runtime.extractLessons(analysis),
74
- publishLevel: "public",
75
- consentSignatures: [],
76
- }),
77
- ).rejects.toMatchObject({
78
- capability: "founder-cemetery",
79
- suggestion: expect.stringContaining("consent"),
80
- });
81
- await expect(readFounderCemeteryDebug(root)).resolves.toEqual(expect.any(Array));
82
- });
83
-
84
- it("refuses non-private memorials with sensitive fields unless redactions are explicit", async () => {
85
- const runtime = await open();
86
- const analysis = await runtime.analyzeDeath({
87
- companyId: "loop",
88
- companyName: "Loop",
89
- timelineSummaries: ["A customer alice@example.com churned during the final sales push"],
90
- });
91
-
92
- await expect(
93
- runtime.publishMemorial({
94
- analysis,
95
- lessons: await runtime.extractLessons(analysis),
96
- publishLevel: "community",
97
- consentSignatures: ["alice"],
98
- }),
99
- ).rejects.toMatchObject({
100
- capability: "founder-cemetery",
101
- suggestion: expect.stringContaining("redactions"),
102
- });
103
- });
104
- });