@compilr-dev/factory 0.1.19 → 0.1.21
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/dist/all-tools.js +2 -0
- package/dist/business-model/defaults.d.ts +7 -0
- package/dist/business-model/defaults.js +54 -0
- package/dist/business-model/index.d.ts +10 -0
- package/dist/business-model/index.js +7 -0
- package/dist/business-model/persistence.d.ts +16 -0
- package/dist/business-model/persistence.js +37 -0
- package/dist/business-model/schema.d.ts +17 -0
- package/dist/business-model/schema.js +126 -0
- package/dist/business-model/tools.d.ts +13 -0
- package/dist/business-model/tools.js +587 -0
- package/dist/business-model/types.d.ts +149 -0
- package/dist/business-model/types.js +7 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/package.json +2 -2
package/dist/all-tools.js
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
import { createModelTools } from './model/tools.js';
|
|
13
13
|
import { createResearchModelTools } from './research-model/tools.js';
|
|
14
14
|
import { createResearchScaffoldTool } from './research-model/scaffold-tool.js';
|
|
15
|
+
import { createBusinessModelTools } from './business-model/tools.js';
|
|
15
16
|
import { createFactoryTools } from './factory/tools.js';
|
|
16
17
|
import { writeFileSync, mkdirSync } from 'fs';
|
|
17
18
|
import { dirname } from 'path';
|
|
@@ -32,6 +33,7 @@ export function createAllFactoryTools(config) {
|
|
|
32
33
|
return [
|
|
33
34
|
...createModelTools({ context: config.context, cwd: config.cwd }),
|
|
34
35
|
...createResearchModelTools({ context: config.context }),
|
|
36
|
+
...createBusinessModelTools({ context: config.context }),
|
|
35
37
|
scaffoldTool,
|
|
36
38
|
...createFactoryTools({ context: config.context, cwd: config.cwd }),
|
|
37
39
|
];
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default Business Model creators.
|
|
3
|
+
*/
|
|
4
|
+
import type { BusinessModel } from './types.js';
|
|
5
|
+
export declare function generateBusinessId(prefix?: string): string;
|
|
6
|
+
export declare function resetBusinessIdCounter(): void;
|
|
7
|
+
export declare function createDefaultBusinessModel(overrides?: Partial<BusinessModel>): BusinessModel;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default Business Model creators.
|
|
3
|
+
*/
|
|
4
|
+
let _idCounter = 0;
|
|
5
|
+
export function generateBusinessId(prefix = 'b') {
|
|
6
|
+
_idCounter++;
|
|
7
|
+
return `${prefix}_${Date.now().toString(36)}_${String(_idCounter)}`;
|
|
8
|
+
}
|
|
9
|
+
export function resetBusinessIdCounter() {
|
|
10
|
+
_idCounter = 0;
|
|
11
|
+
}
|
|
12
|
+
export function createDefaultBusinessModel(overrides) {
|
|
13
|
+
const now = new Date().toISOString();
|
|
14
|
+
return {
|
|
15
|
+
identity: {
|
|
16
|
+
name: 'My Business',
|
|
17
|
+
stage: 'idea',
|
|
18
|
+
...overrides?.identity,
|
|
19
|
+
},
|
|
20
|
+
valueProposition: {
|
|
21
|
+
problem: '',
|
|
22
|
+
solution: '',
|
|
23
|
+
uniqueValue: '',
|
|
24
|
+
...overrides?.valueProposition,
|
|
25
|
+
},
|
|
26
|
+
market: {
|
|
27
|
+
segments: [],
|
|
28
|
+
...overrides?.market,
|
|
29
|
+
},
|
|
30
|
+
competitors: overrides?.competitors ?? [],
|
|
31
|
+
competitiveAdvantages: overrides?.competitiveAdvantages,
|
|
32
|
+
canvas: {
|
|
33
|
+
revenueStreams: [],
|
|
34
|
+
costStructure: [],
|
|
35
|
+
...overrides?.canvas,
|
|
36
|
+
},
|
|
37
|
+
financials: {
|
|
38
|
+
revenueForecasts: [],
|
|
39
|
+
expenseForecasts: [],
|
|
40
|
+
...overrides?.financials,
|
|
41
|
+
},
|
|
42
|
+
goToMarket: {
|
|
43
|
+
phases: [],
|
|
44
|
+
...overrides?.goToMarket,
|
|
45
|
+
},
|
|
46
|
+
team: overrides?.team,
|
|
47
|
+
meta: {
|
|
48
|
+
revision: 1,
|
|
49
|
+
createdAt: now,
|
|
50
|
+
updatedAt: now,
|
|
51
|
+
...overrides?.meta,
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Business Model — barrel export
|
|
3
|
+
*/
|
|
4
|
+
export type { BusinessModel, BusinessIdentity, BusinessStage, ValueProposition, Market, MarketSize, CustomerSegment, Competitor, MarketPosition, BusinessCanvas, RevenueStream, RevenueType, CostItem, Financials, ForecastEntry, GoToMarket, GTMPhase, TeamMember, BusinessMeta, PositioningMatrix, } from './types.js';
|
|
5
|
+
export { createDefaultBusinessModel, generateBusinessId, resetBusinessIdCounter, } from './defaults.js';
|
|
6
|
+
export { BusinessModelStore } from './persistence.js';
|
|
7
|
+
export { validateBusinessModel } from './schema.js';
|
|
8
|
+
export type { BusinessValidationError, BusinessValidationResult } from './schema.js';
|
|
9
|
+
export { createBusinessModelTools } from './tools.js';
|
|
10
|
+
export type { BusinessModelToolsConfig } from './tools.js';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Business Model — barrel export
|
|
3
|
+
*/
|
|
4
|
+
export { createDefaultBusinessModel, generateBusinessId, resetBusinessIdCounter, } from './defaults.js';
|
|
5
|
+
export { BusinessModelStore } from './persistence.js';
|
|
6
|
+
export { validateBusinessModel } from './schema.js';
|
|
7
|
+
export { createBusinessModelTools } from './tools.js';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Business Model Store — Persistence Layer
|
|
3
|
+
*/
|
|
4
|
+
import type { IDocumentRepository } from '@compilr-dev/sdk';
|
|
5
|
+
import type { BusinessModel } from './types.js';
|
|
6
|
+
export declare class BusinessModelStore {
|
|
7
|
+
private readonly documents;
|
|
8
|
+
private readonly projectId;
|
|
9
|
+
constructor(config: {
|
|
10
|
+
documents: IDocumentRepository;
|
|
11
|
+
projectId: number;
|
|
12
|
+
});
|
|
13
|
+
get(): Promise<BusinessModel | null>;
|
|
14
|
+
save(model: BusinessModel): Promise<void>;
|
|
15
|
+
exists(): Promise<boolean>;
|
|
16
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Business Model Store — Persistence Layer
|
|
3
|
+
*/
|
|
4
|
+
const BIZ_MODEL_DOC_TYPE = 'business-model';
|
|
5
|
+
const BIZ_MODEL_TITLE = 'Business Model';
|
|
6
|
+
export class BusinessModelStore {
|
|
7
|
+
documents;
|
|
8
|
+
projectId;
|
|
9
|
+
constructor(config) {
|
|
10
|
+
this.documents = config.documents;
|
|
11
|
+
this.projectId = config.projectId;
|
|
12
|
+
}
|
|
13
|
+
async get() {
|
|
14
|
+
const doc = await this.documents.getByType(this.projectId, BIZ_MODEL_DOC_TYPE);
|
|
15
|
+
if (!doc)
|
|
16
|
+
return null;
|
|
17
|
+
try {
|
|
18
|
+
return JSON.parse(doc.content);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
async save(model) {
|
|
25
|
+
const content = JSON.stringify(model, null, 2);
|
|
26
|
+
await this.documents.upsert({
|
|
27
|
+
project_id: this.projectId,
|
|
28
|
+
doc_type: BIZ_MODEL_DOC_TYPE,
|
|
29
|
+
title: BIZ_MODEL_TITLE,
|
|
30
|
+
content,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
async exists() {
|
|
34
|
+
const doc = await this.documents.getByType(this.projectId, BIZ_MODEL_DOC_TYPE);
|
|
35
|
+
return doc !== null;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Business Model Validation
|
|
3
|
+
*
|
|
4
|
+
* Structural validation + business-quality warnings.
|
|
5
|
+
*/
|
|
6
|
+
import type { BusinessModel } from './types.js';
|
|
7
|
+
export interface BusinessValidationError {
|
|
8
|
+
readonly path: string;
|
|
9
|
+
readonly message: string;
|
|
10
|
+
readonly severity: 'error' | 'warning';
|
|
11
|
+
}
|
|
12
|
+
export interface BusinessValidationResult {
|
|
13
|
+
readonly valid: boolean;
|
|
14
|
+
readonly errors: readonly BusinessValidationError[];
|
|
15
|
+
readonly warnings: readonly BusinessValidationError[];
|
|
16
|
+
}
|
|
17
|
+
export declare function validateBusinessModel(model: BusinessModel): BusinessValidationResult;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Business Model Validation
|
|
3
|
+
*
|
|
4
|
+
* Structural validation + business-quality warnings.
|
|
5
|
+
*/
|
|
6
|
+
export function validateBusinessModel(model) {
|
|
7
|
+
const errors = [];
|
|
8
|
+
const warnings = [];
|
|
9
|
+
// ── Structural errors ──────────────────────────────────────────────────
|
|
10
|
+
if (!model.identity.name || model.identity.name.trim().length === 0) {
|
|
11
|
+
errors.push({ path: 'identity.name', message: 'Business name is required', severity: 'error' });
|
|
12
|
+
}
|
|
13
|
+
// Duplicate competitor IDs
|
|
14
|
+
const compIds = new Set();
|
|
15
|
+
for (const c of model.competitors) {
|
|
16
|
+
if (compIds.has(c.id)) {
|
|
17
|
+
errors.push({
|
|
18
|
+
path: `competitors[${c.id}]`,
|
|
19
|
+
message: `Duplicate competitor id "${c.id}"`,
|
|
20
|
+
severity: 'error',
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
compIds.add(c.id);
|
|
24
|
+
if (!c.name.trim()) {
|
|
25
|
+
errors.push({
|
|
26
|
+
path: `competitors[${c.id}].name`,
|
|
27
|
+
message: 'Competitor name is required',
|
|
28
|
+
severity: 'error',
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
// Duplicate segment IDs
|
|
33
|
+
const segIds = new Set();
|
|
34
|
+
for (const s of model.market.segments) {
|
|
35
|
+
if (segIds.has(s.id)) {
|
|
36
|
+
errors.push({
|
|
37
|
+
path: `market.segments[${s.id}]`,
|
|
38
|
+
message: `Duplicate segment id "${s.id}"`,
|
|
39
|
+
severity: 'error',
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
segIds.add(s.id);
|
|
43
|
+
}
|
|
44
|
+
// Duplicate revenue stream IDs
|
|
45
|
+
const rsIds = new Set();
|
|
46
|
+
for (const r of model.canvas.revenueStreams) {
|
|
47
|
+
if (rsIds.has(r.id)) {
|
|
48
|
+
errors.push({
|
|
49
|
+
path: `canvas.revenueStreams[${r.id}]`,
|
|
50
|
+
message: `Duplicate revenue stream id "${r.id}"`,
|
|
51
|
+
severity: 'error',
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
rsIds.add(r.id);
|
|
55
|
+
}
|
|
56
|
+
// ── Business quality warnings ──────────────────────────────────────────
|
|
57
|
+
if (!model.valueProposition.problem) {
|
|
58
|
+
warnings.push({
|
|
59
|
+
path: 'valueProposition.problem',
|
|
60
|
+
message: 'Problem statement is empty',
|
|
61
|
+
severity: 'warning',
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
if (!model.valueProposition.solution) {
|
|
65
|
+
warnings.push({
|
|
66
|
+
path: 'valueProposition.solution',
|
|
67
|
+
message: 'Solution is empty',
|
|
68
|
+
severity: 'warning',
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
if (!model.valueProposition.uniqueValue) {
|
|
72
|
+
warnings.push({
|
|
73
|
+
path: 'valueProposition.uniqueValue',
|
|
74
|
+
message: 'Unique value proposition is empty',
|
|
75
|
+
severity: 'warning',
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
if (!model.market.tam && !model.market.sam && !model.market.som) {
|
|
79
|
+
warnings.push({
|
|
80
|
+
path: 'market',
|
|
81
|
+
message: 'No market sizing defined (TAM/SAM/SOM)',
|
|
82
|
+
severity: 'warning',
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
if (model.market.segments.length === 0) {
|
|
86
|
+
warnings.push({
|
|
87
|
+
path: 'market.segments',
|
|
88
|
+
message: 'No customer segments defined',
|
|
89
|
+
severity: 'warning',
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
if (model.competitors.length === 0) {
|
|
93
|
+
warnings.push({
|
|
94
|
+
path: 'competitors',
|
|
95
|
+
message: 'No competitors identified',
|
|
96
|
+
severity: 'warning',
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
if (model.canvas.revenueStreams.length === 0) {
|
|
100
|
+
warnings.push({
|
|
101
|
+
path: 'canvas.revenueStreams',
|
|
102
|
+
message: 'No revenue streams defined',
|
|
103
|
+
severity: 'warning',
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
if (model.financials.revenueForecasts.length === 0 &&
|
|
107
|
+
model.financials.expenseForecasts.length === 0) {
|
|
108
|
+
warnings.push({
|
|
109
|
+
path: 'financials',
|
|
110
|
+
message: 'No financial projections defined',
|
|
111
|
+
severity: 'warning',
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
if (model.goToMarket.phases.length === 0) {
|
|
115
|
+
warnings.push({
|
|
116
|
+
path: 'goToMarket.phases',
|
|
117
|
+
message: 'No go-to-market phases defined',
|
|
118
|
+
severity: 'warning',
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
valid: errors.length === 0,
|
|
123
|
+
errors,
|
|
124
|
+
warnings,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Business Model Tools
|
|
3
|
+
*
|
|
4
|
+
* business_model_get — scoped reads
|
|
5
|
+
* business_model_update — semantic operations
|
|
6
|
+
* business_model_validate — check completeness
|
|
7
|
+
*/
|
|
8
|
+
import type { Tool } from '@compilr-dev/agents';
|
|
9
|
+
import type { PlatformContext } from '@compilr-dev/sdk';
|
|
10
|
+
export interface BusinessModelToolsConfig {
|
|
11
|
+
readonly context: PlatformContext;
|
|
12
|
+
}
|
|
13
|
+
export declare function createBusinessModelTools(config: BusinessModelToolsConfig): Tool<never>[];
|
|
@@ -0,0 +1,587 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Business Model Tools
|
|
3
|
+
*
|
|
4
|
+
* business_model_get — scoped reads
|
|
5
|
+
* business_model_update — semantic operations
|
|
6
|
+
* business_model_validate — check completeness
|
|
7
|
+
*/
|
|
8
|
+
import { defineTool, createSuccessResult, createErrorResult } from '@compilr-dev/agents';
|
|
9
|
+
import { BusinessModelStore } from './persistence.js';
|
|
10
|
+
import { validateBusinessModel } from './schema.js';
|
|
11
|
+
import { createDefaultBusinessModel, generateBusinessId } from './defaults.js';
|
|
12
|
+
function getProjectId(config, inputProjectId) {
|
|
13
|
+
const projectId = inputProjectId ?? config.context.currentProjectId;
|
|
14
|
+
if (!projectId)
|
|
15
|
+
throw new Error('No active project.');
|
|
16
|
+
return projectId;
|
|
17
|
+
}
|
|
18
|
+
function createStore(config, projectId) {
|
|
19
|
+
return new BusinessModelStore({ documents: config.context.documents, projectId });
|
|
20
|
+
}
|
|
21
|
+
function createBizModelGetTool(config) {
|
|
22
|
+
return defineTool({
|
|
23
|
+
name: 'business_model_get',
|
|
24
|
+
description: 'Read the Business Model. Supports scoped reads by section.',
|
|
25
|
+
inputSchema: {
|
|
26
|
+
type: 'object',
|
|
27
|
+
properties: {
|
|
28
|
+
scope: {
|
|
29
|
+
type: 'string',
|
|
30
|
+
enum: [
|
|
31
|
+
'overview',
|
|
32
|
+
'identity',
|
|
33
|
+
'market',
|
|
34
|
+
'competitors',
|
|
35
|
+
'canvas',
|
|
36
|
+
'financials',
|
|
37
|
+
'gtm',
|
|
38
|
+
'team',
|
|
39
|
+
'full',
|
|
40
|
+
],
|
|
41
|
+
description: 'Which section to return. "overview" for summary. Omit or "full" for everything.',
|
|
42
|
+
},
|
|
43
|
+
project_id: { type: 'number', description: 'Project ID. Uses active project if omitted.' },
|
|
44
|
+
},
|
|
45
|
+
required: [],
|
|
46
|
+
},
|
|
47
|
+
execute: async (input) => {
|
|
48
|
+
try {
|
|
49
|
+
const projectId = getProjectId(config, input.project_id);
|
|
50
|
+
const model = await createStore(config, projectId).get();
|
|
51
|
+
if (!model) {
|
|
52
|
+
return createSuccessResult({
|
|
53
|
+
exists: false,
|
|
54
|
+
message: 'No Business Model found. Use business_model_update to start building one.',
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
switch (input.scope) {
|
|
58
|
+
case 'overview':
|
|
59
|
+
return createSuccessResult({
|
|
60
|
+
name: model.identity.name,
|
|
61
|
+
stage: model.identity.stage,
|
|
62
|
+
problem: model.valueProposition.problem,
|
|
63
|
+
segments: model.market.segments.length,
|
|
64
|
+
competitors: model.competitors.length,
|
|
65
|
+
revenueStreams: model.canvas.revenueStreams.length,
|
|
66
|
+
phases: model.goToMarket.phases.length,
|
|
67
|
+
revision: model.meta.revision,
|
|
68
|
+
});
|
|
69
|
+
case 'identity':
|
|
70
|
+
return createSuccessResult({
|
|
71
|
+
identity: model.identity,
|
|
72
|
+
valueProposition: model.valueProposition,
|
|
73
|
+
meta: model.meta,
|
|
74
|
+
});
|
|
75
|
+
case 'market':
|
|
76
|
+
return createSuccessResult({ market: model.market, meta: model.meta });
|
|
77
|
+
case 'competitors':
|
|
78
|
+
return createSuccessResult({
|
|
79
|
+
competitors: model.competitors,
|
|
80
|
+
competitiveAdvantages: model.competitiveAdvantages,
|
|
81
|
+
meta: model.meta,
|
|
82
|
+
});
|
|
83
|
+
case 'canvas':
|
|
84
|
+
return createSuccessResult({ canvas: model.canvas, meta: model.meta });
|
|
85
|
+
case 'financials':
|
|
86
|
+
return createSuccessResult({ financials: model.financials, meta: model.meta });
|
|
87
|
+
case 'gtm':
|
|
88
|
+
return createSuccessResult({ goToMarket: model.goToMarket, meta: model.meta });
|
|
89
|
+
case 'team':
|
|
90
|
+
return createSuccessResult({ team: model.team, meta: model.meta });
|
|
91
|
+
default:
|
|
92
|
+
return createSuccessResult(model);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
return createErrorResult(error instanceof Error ? error.message : String(error));
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
readonly: true,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
const ALL_OPS = [
|
|
103
|
+
'set_identity',
|
|
104
|
+
'set_value_proposition',
|
|
105
|
+
'set_market_size',
|
|
106
|
+
'segment_add',
|
|
107
|
+
'segment_update',
|
|
108
|
+
'segment_remove',
|
|
109
|
+
'competitor_add',
|
|
110
|
+
'competitor_update',
|
|
111
|
+
'competitor_remove',
|
|
112
|
+
'set_competitive_advantages',
|
|
113
|
+
'revenue_stream_add',
|
|
114
|
+
'revenue_stream_update',
|
|
115
|
+
'revenue_stream_remove',
|
|
116
|
+
'cost_item_add',
|
|
117
|
+
'cost_item_update',
|
|
118
|
+
'cost_item_remove',
|
|
119
|
+
'set_canvas_fields',
|
|
120
|
+
'forecast_add',
|
|
121
|
+
'set_financials_fields',
|
|
122
|
+
'phase_add',
|
|
123
|
+
'phase_update',
|
|
124
|
+
'phase_remove',
|
|
125
|
+
'set_gtm_fields',
|
|
126
|
+
'set_team',
|
|
127
|
+
'set_positioning',
|
|
128
|
+
];
|
|
129
|
+
function createBizModelUpdateTool(config) {
|
|
130
|
+
return defineTool({
|
|
131
|
+
name: 'business_model_update',
|
|
132
|
+
description: 'Apply a semantic operation to the Business Model. Auto-creates if none exists.',
|
|
133
|
+
inputSchema: {
|
|
134
|
+
type: 'object',
|
|
135
|
+
properties: {
|
|
136
|
+
op: { type: 'string', enum: [...ALL_OPS], description: 'The operation to perform.' },
|
|
137
|
+
revision: { type: 'number', description: 'Expected revision for optimistic locking.' },
|
|
138
|
+
identity: {
|
|
139
|
+
oneOf: [{ type: 'object', additionalProperties: true }, { type: 'string' }],
|
|
140
|
+
description: 'For set_identity: { name, tagline, mission, stage, industry, sector }',
|
|
141
|
+
},
|
|
142
|
+
value_proposition: {
|
|
143
|
+
oneOf: [{ type: 'object', additionalProperties: true }, { type: 'string' }],
|
|
144
|
+
description: 'For set_value_proposition: { problem, solution, uniqueValue, targetCustomer }',
|
|
145
|
+
},
|
|
146
|
+
market_size: {
|
|
147
|
+
oneOf: [{ type: 'object', additionalProperties: true }, { type: 'string' }],
|
|
148
|
+
description: 'For set_market_size: { tam?, sam?, som?, trends?, growthRate? }',
|
|
149
|
+
},
|
|
150
|
+
segment: {
|
|
151
|
+
oneOf: [{ type: 'object', additionalProperties: true }, { type: 'string' }],
|
|
152
|
+
description: 'For segment_add/update: { name, description, size, painPoints, willingness }',
|
|
153
|
+
},
|
|
154
|
+
segment_id: { type: 'string', description: 'Segment ID for update/remove.' },
|
|
155
|
+
competitor: {
|
|
156
|
+
oneOf: [{ type: 'object', additionalProperties: true }, { type: 'string' }],
|
|
157
|
+
description: 'For competitor_add/update: { name, description, strengths, weaknesses, marketPosition, pricing, url }',
|
|
158
|
+
},
|
|
159
|
+
competitor_id: { type: 'string', description: 'Competitor ID for update/remove.' },
|
|
160
|
+
advantages: {
|
|
161
|
+
type: 'array',
|
|
162
|
+
items: { type: 'string' },
|
|
163
|
+
description: 'For set_competitive_advantages.',
|
|
164
|
+
},
|
|
165
|
+
revenue_stream: {
|
|
166
|
+
oneOf: [{ type: 'object', additionalProperties: true }, { type: 'string' }],
|
|
167
|
+
description: 'For revenue_stream_add/update: { name, type, description, projectedRevenue }',
|
|
168
|
+
},
|
|
169
|
+
stream_id: { type: 'string', description: 'Revenue stream ID for update/remove.' },
|
|
170
|
+
cost_item: {
|
|
171
|
+
oneOf: [{ type: 'object', additionalProperties: true }, { type: 'string' }],
|
|
172
|
+
description: 'For cost_item_add/update: { category, name, amount, frequency }',
|
|
173
|
+
},
|
|
174
|
+
cost_id: { type: 'string', description: 'Cost item ID for update/remove.' },
|
|
175
|
+
canvas_field: {
|
|
176
|
+
oneOf: [{ type: 'object', additionalProperties: true }, { type: 'string' }],
|
|
177
|
+
description: 'For set_canvas_fields: { keyResources?, keyActivities?, keyPartnerships?, channels?, customerRelationships? }',
|
|
178
|
+
},
|
|
179
|
+
financials_field: {
|
|
180
|
+
oneOf: [{ type: 'object', additionalProperties: true }, { type: 'string' }],
|
|
181
|
+
description: 'For set_financials_fields: { breakEvenPoint?, fundingNeeds?, useOfFunds?, assumptions? }',
|
|
182
|
+
},
|
|
183
|
+
phase: {
|
|
184
|
+
oneOf: [{ type: 'object', additionalProperties: true }, { type: 'string' }],
|
|
185
|
+
description: 'For phase_add/update: { name, description, targetDate, milestones }',
|
|
186
|
+
},
|
|
187
|
+
phase_id: { type: 'string', description: 'GTM phase ID for update/remove.' },
|
|
188
|
+
updates: {
|
|
189
|
+
oneOf: [{ type: 'object', additionalProperties: true }, { type: 'string' }],
|
|
190
|
+
description: 'Partial updates for update operations.',
|
|
191
|
+
},
|
|
192
|
+
team: {
|
|
193
|
+
type: 'array',
|
|
194
|
+
items: { type: 'object', additionalProperties: true },
|
|
195
|
+
description: 'For set_team: [{ name, role, background }]',
|
|
196
|
+
},
|
|
197
|
+
positioning: {
|
|
198
|
+
oneOf: [{ type: 'object', additionalProperties: true }, { type: 'string' }],
|
|
199
|
+
description: 'For set_positioning: { xAxis, yAxis, selfX (0-100), selfY (0-100), xLow?, xHigh?, yLow?, yHigh? }. Competitors need positionX/positionY set via competitor_update.',
|
|
200
|
+
},
|
|
201
|
+
project_id: { type: 'number', description: 'Project ID. Uses active project if omitted.' },
|
|
202
|
+
},
|
|
203
|
+
required: ['op'],
|
|
204
|
+
},
|
|
205
|
+
execute: async (input) => {
|
|
206
|
+
try {
|
|
207
|
+
const projectId = getProjectId(config, input.project_id);
|
|
208
|
+
const store = createStore(config, projectId);
|
|
209
|
+
let model = await store.get();
|
|
210
|
+
if (!model)
|
|
211
|
+
model = createDefaultBusinessModel();
|
|
212
|
+
if (input.revision !== undefined && input.revision !== model.meta.revision) {
|
|
213
|
+
return createErrorResult(`Revision conflict: expected ${String(input.revision)}, current is ${String(model.meta.revision)}.`);
|
|
214
|
+
}
|
|
215
|
+
const updated = applyOperation(model, input);
|
|
216
|
+
const validation = validateBusinessModel(updated);
|
|
217
|
+
if (!validation.valid) {
|
|
218
|
+
const msgs = validation.errors.map((e) => `${e.path}: ${e.message}`).join('; ');
|
|
219
|
+
return createErrorResult(`Operation would produce invalid model: ${msgs}`);
|
|
220
|
+
}
|
|
221
|
+
await store.save(updated);
|
|
222
|
+
return createSuccessResult({
|
|
223
|
+
op: input.op,
|
|
224
|
+
revision: updated.meta.revision,
|
|
225
|
+
message: `Operation "${input.op}" applied successfully.`,
|
|
226
|
+
warnings: validation.warnings.length > 0
|
|
227
|
+
? validation.warnings.map((w) => `${w.path}: ${w.message}`)
|
|
228
|
+
: undefined,
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
catch (error) {
|
|
232
|
+
return createErrorResult(error instanceof Error ? error.message : String(error));
|
|
233
|
+
}
|
|
234
|
+
},
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
// =============================================================================
|
|
238
|
+
// Operation dispatcher
|
|
239
|
+
// =============================================================================
|
|
240
|
+
function coerce(value) {
|
|
241
|
+
if (typeof value === 'object' && value !== null && !Array.isArray(value))
|
|
242
|
+
return value;
|
|
243
|
+
if (typeof value === 'string') {
|
|
244
|
+
try {
|
|
245
|
+
const p = JSON.parse(value);
|
|
246
|
+
if (typeof p === 'object' && p !== null && !Array.isArray(p))
|
|
247
|
+
return p;
|
|
248
|
+
}
|
|
249
|
+
catch {
|
|
250
|
+
/* not JSON */
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
255
|
+
function bump(model) {
|
|
256
|
+
return {
|
|
257
|
+
...model,
|
|
258
|
+
meta: { ...model.meta, revision: model.meta.revision + 1, updatedAt: new Date().toISOString() },
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
function applyOperation(model, input) {
|
|
262
|
+
switch (input.op) {
|
|
263
|
+
case 'set_identity': {
|
|
264
|
+
const data = coerce(input.identity);
|
|
265
|
+
if (!data)
|
|
266
|
+
throw new Error('set_identity requires "identity" object.');
|
|
267
|
+
return bump({
|
|
268
|
+
...model,
|
|
269
|
+
identity: { ...model.identity, ...data },
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
case 'set_value_proposition': {
|
|
273
|
+
const data = coerce(input.value_proposition);
|
|
274
|
+
if (!data)
|
|
275
|
+
throw new Error('set_value_proposition requires "value_proposition" object.');
|
|
276
|
+
return bump({
|
|
277
|
+
...model,
|
|
278
|
+
valueProposition: {
|
|
279
|
+
...model.valueProposition,
|
|
280
|
+
...data,
|
|
281
|
+
},
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
case 'set_market_size': {
|
|
285
|
+
const data = coerce(input.market_size);
|
|
286
|
+
if (!data)
|
|
287
|
+
throw new Error('set_market_size requires "market_size" object.');
|
|
288
|
+
return bump({ ...model, market: { ...model.market, ...data } });
|
|
289
|
+
}
|
|
290
|
+
case 'segment_add': {
|
|
291
|
+
const data = coerce(input.segment);
|
|
292
|
+
if (!data)
|
|
293
|
+
throw new Error('segment_add requires "segment" object with "name".');
|
|
294
|
+
const seg = {
|
|
295
|
+
id: generateBusinessId('seg'),
|
|
296
|
+
...data,
|
|
297
|
+
};
|
|
298
|
+
return bump({
|
|
299
|
+
...model,
|
|
300
|
+
market: { ...model.market, segments: [...model.market.segments, seg] },
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
case 'segment_update': {
|
|
304
|
+
if (!input.segment_id)
|
|
305
|
+
throw new Error('segment_update requires "segment_id".');
|
|
306
|
+
const data = coerce(input.updates ?? input.segment);
|
|
307
|
+
if (!data)
|
|
308
|
+
throw new Error('segment_update requires "updates" object.');
|
|
309
|
+
return bump({
|
|
310
|
+
...model,
|
|
311
|
+
market: {
|
|
312
|
+
...model.market,
|
|
313
|
+
segments: model.market.segments.map((s) => s.id === input.segment_id ? { ...s, ...data, id: s.id } : s),
|
|
314
|
+
},
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
case 'segment_remove': {
|
|
318
|
+
if (!input.segment_id)
|
|
319
|
+
throw new Error('segment_remove requires "segment_id".');
|
|
320
|
+
return bump({
|
|
321
|
+
...model,
|
|
322
|
+
market: {
|
|
323
|
+
...model.market,
|
|
324
|
+
segments: model.market.segments.filter((s) => s.id !== input.segment_id),
|
|
325
|
+
},
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
case 'competitor_add': {
|
|
329
|
+
const data = coerce(input.competitor);
|
|
330
|
+
if (!data)
|
|
331
|
+
throw new Error('competitor_add requires "competitor" object with "name".');
|
|
332
|
+
const comp = {
|
|
333
|
+
id: generateBusinessId('comp'),
|
|
334
|
+
strengths: [],
|
|
335
|
+
weaknesses: [],
|
|
336
|
+
...data,
|
|
337
|
+
};
|
|
338
|
+
if (model.competitors.some((c) => c.name === comp.name))
|
|
339
|
+
throw new Error(`Competitor "${comp.name}" already exists.`);
|
|
340
|
+
return bump({ ...model, competitors: [...model.competitors, comp] });
|
|
341
|
+
}
|
|
342
|
+
case 'competitor_update': {
|
|
343
|
+
if (!input.competitor_id)
|
|
344
|
+
throw new Error('competitor_update requires "competitor_id".');
|
|
345
|
+
const data = coerce(input.updates ?? input.competitor);
|
|
346
|
+
if (!data)
|
|
347
|
+
throw new Error('competitor_update requires "updates" object.');
|
|
348
|
+
return bump({
|
|
349
|
+
...model,
|
|
350
|
+
competitors: model.competitors.map((c) => c.id === input.competitor_id ? { ...c, ...data, id: c.id } : c),
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
case 'competitor_remove': {
|
|
354
|
+
if (!input.competitor_id)
|
|
355
|
+
throw new Error('competitor_remove requires "competitor_id".');
|
|
356
|
+
return bump({
|
|
357
|
+
...model,
|
|
358
|
+
competitors: model.competitors.filter((c) => c.id !== input.competitor_id),
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
case 'set_competitive_advantages': {
|
|
362
|
+
if (!input.advantages)
|
|
363
|
+
throw new Error('set_competitive_advantages requires "advantages" array.');
|
|
364
|
+
return bump({ ...model, competitiveAdvantages: input.advantages });
|
|
365
|
+
}
|
|
366
|
+
case 'revenue_stream_add': {
|
|
367
|
+
const data = coerce(input.revenue_stream);
|
|
368
|
+
if (!data)
|
|
369
|
+
throw new Error('revenue_stream_add requires "revenue_stream" object.');
|
|
370
|
+
const rs = {
|
|
371
|
+
id: generateBusinessId('rs'),
|
|
372
|
+
...data,
|
|
373
|
+
};
|
|
374
|
+
return bump({
|
|
375
|
+
...model,
|
|
376
|
+
canvas: { ...model.canvas, revenueStreams: [...model.canvas.revenueStreams, rs] },
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
case 'revenue_stream_update': {
|
|
380
|
+
if (!input.stream_id)
|
|
381
|
+
throw new Error('revenue_stream_update requires "stream_id".');
|
|
382
|
+
const data = coerce(input.updates ?? input.revenue_stream);
|
|
383
|
+
if (!data)
|
|
384
|
+
throw new Error('revenue_stream_update requires "updates" object.');
|
|
385
|
+
return bump({
|
|
386
|
+
...model,
|
|
387
|
+
canvas: {
|
|
388
|
+
...model.canvas,
|
|
389
|
+
revenueStreams: model.canvas.revenueStreams.map((r) => r.id === input.stream_id ? { ...r, ...data, id: r.id } : r),
|
|
390
|
+
},
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
case 'revenue_stream_remove': {
|
|
394
|
+
if (!input.stream_id)
|
|
395
|
+
throw new Error('revenue_stream_remove requires "stream_id".');
|
|
396
|
+
return bump({
|
|
397
|
+
...model,
|
|
398
|
+
canvas: {
|
|
399
|
+
...model.canvas,
|
|
400
|
+
revenueStreams: model.canvas.revenueStreams.filter((r) => r.id !== input.stream_id),
|
|
401
|
+
},
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
case 'cost_item_add': {
|
|
405
|
+
const data = coerce(input.cost_item);
|
|
406
|
+
if (!data)
|
|
407
|
+
throw new Error('cost_item_add requires "cost_item" object.');
|
|
408
|
+
const ci = { id: generateBusinessId('ci'), ...data };
|
|
409
|
+
return bump({
|
|
410
|
+
...model,
|
|
411
|
+
canvas: { ...model.canvas, costStructure: [...model.canvas.costStructure, ci] },
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
case 'cost_item_update': {
|
|
415
|
+
if (!input.cost_id)
|
|
416
|
+
throw new Error('cost_item_update requires "cost_id".');
|
|
417
|
+
const data = coerce(input.updates ?? input.cost_item);
|
|
418
|
+
if (!data)
|
|
419
|
+
throw new Error('cost_item_update requires "updates" object.');
|
|
420
|
+
return bump({
|
|
421
|
+
...model,
|
|
422
|
+
canvas: {
|
|
423
|
+
...model.canvas,
|
|
424
|
+
costStructure: model.canvas.costStructure.map((c) => c.id === input.cost_id ? { ...c, ...data, id: c.id } : c),
|
|
425
|
+
},
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
case 'cost_item_remove': {
|
|
429
|
+
if (!input.cost_id)
|
|
430
|
+
throw new Error('cost_item_remove requires "cost_id".');
|
|
431
|
+
return bump({
|
|
432
|
+
...model,
|
|
433
|
+
canvas: {
|
|
434
|
+
...model.canvas,
|
|
435
|
+
costStructure: model.canvas.costStructure.filter((c) => c.id !== input.cost_id),
|
|
436
|
+
},
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
case 'set_canvas_fields': {
|
|
440
|
+
const data = coerce(input.canvas_field);
|
|
441
|
+
if (!data)
|
|
442
|
+
throw new Error('set_canvas_fields requires "canvas_field" object.');
|
|
443
|
+
return bump({ ...model, canvas: { ...model.canvas, ...data } });
|
|
444
|
+
}
|
|
445
|
+
case 'forecast_add': {
|
|
446
|
+
const data = coerce(input.financials_field);
|
|
447
|
+
if (!data)
|
|
448
|
+
throw new Error('forecast_add requires "financials_field" with period, category, amount.');
|
|
449
|
+
const isRevenue = data.type === 'revenue';
|
|
450
|
+
const entry = {
|
|
451
|
+
period: data.period,
|
|
452
|
+
category: data.category,
|
|
453
|
+
amount: data.amount,
|
|
454
|
+
notes: data.notes,
|
|
455
|
+
};
|
|
456
|
+
if (isRevenue) {
|
|
457
|
+
return bump({
|
|
458
|
+
...model,
|
|
459
|
+
financials: {
|
|
460
|
+
...model.financials,
|
|
461
|
+
revenueForecasts: [...model.financials.revenueForecasts, entry],
|
|
462
|
+
},
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
return bump({
|
|
466
|
+
...model,
|
|
467
|
+
financials: {
|
|
468
|
+
...model.financials,
|
|
469
|
+
expenseForecasts: [...model.financials.expenseForecasts, entry],
|
|
470
|
+
},
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
case 'set_financials_fields': {
|
|
474
|
+
const data = coerce(input.financials_field);
|
|
475
|
+
if (!data)
|
|
476
|
+
throw new Error('set_financials_fields requires "financials_field" object.');
|
|
477
|
+
return bump({
|
|
478
|
+
...model,
|
|
479
|
+
financials: { ...model.financials, ...data },
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
case 'phase_add': {
|
|
483
|
+
const data = coerce(input.phase);
|
|
484
|
+
if (!data)
|
|
485
|
+
throw new Error('phase_add requires "phase" object with "name".');
|
|
486
|
+
const ph = { id: generateBusinessId('ph'), ...data };
|
|
487
|
+
return bump({
|
|
488
|
+
...model,
|
|
489
|
+
goToMarket: { ...model.goToMarket, phases: [...model.goToMarket.phases, ph] },
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
case 'phase_update': {
|
|
493
|
+
if (!input.phase_id)
|
|
494
|
+
throw new Error('phase_update requires "phase_id".');
|
|
495
|
+
const data = coerce(input.updates ?? input.phase);
|
|
496
|
+
if (!data)
|
|
497
|
+
throw new Error('phase_update requires "updates" object.');
|
|
498
|
+
return bump({
|
|
499
|
+
...model,
|
|
500
|
+
goToMarket: {
|
|
501
|
+
...model.goToMarket,
|
|
502
|
+
phases: model.goToMarket.phases.map((p) => p.id === input.phase_id ? { ...p, ...data, id: p.id } : p),
|
|
503
|
+
},
|
|
504
|
+
});
|
|
505
|
+
}
|
|
506
|
+
case 'phase_remove': {
|
|
507
|
+
if (!input.phase_id)
|
|
508
|
+
throw new Error('phase_remove requires "phase_id".');
|
|
509
|
+
return bump({
|
|
510
|
+
...model,
|
|
511
|
+
goToMarket: {
|
|
512
|
+
...model.goToMarket,
|
|
513
|
+
phases: model.goToMarket.phases.filter((p) => p.id !== input.phase_id),
|
|
514
|
+
},
|
|
515
|
+
});
|
|
516
|
+
}
|
|
517
|
+
case 'set_gtm_fields': {
|
|
518
|
+
const data = coerce(input.updates);
|
|
519
|
+
if (!data)
|
|
520
|
+
throw new Error('set_gtm_fields requires "updates" object.');
|
|
521
|
+
return bump({
|
|
522
|
+
...model,
|
|
523
|
+
goToMarket: { ...model.goToMarket, ...data },
|
|
524
|
+
});
|
|
525
|
+
}
|
|
526
|
+
case 'set_team': {
|
|
527
|
+
if (!input.team)
|
|
528
|
+
throw new Error('set_team requires "team" array.');
|
|
529
|
+
return bump({ ...model, team: input.team });
|
|
530
|
+
}
|
|
531
|
+
case 'set_positioning': {
|
|
532
|
+
const data = coerce(input.positioning);
|
|
533
|
+
if (!data)
|
|
534
|
+
throw new Error('set_positioning requires "positioning" object with xAxis, yAxis, selfX, selfY.');
|
|
535
|
+
return bump({ ...model, positioning: data });
|
|
536
|
+
}
|
|
537
|
+
default:
|
|
538
|
+
throw new Error(`Unknown operation: ${input.op}`);
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
function createBizModelValidateTool(config) {
|
|
542
|
+
return defineTool({
|
|
543
|
+
name: 'business_model_validate',
|
|
544
|
+
description: 'Validate the Business Model. Returns structural errors and business-quality warnings.',
|
|
545
|
+
inputSchema: {
|
|
546
|
+
type: 'object',
|
|
547
|
+
properties: {
|
|
548
|
+
project_id: { type: 'number', description: 'Project ID. Uses active project if omitted.' },
|
|
549
|
+
},
|
|
550
|
+
required: [],
|
|
551
|
+
},
|
|
552
|
+
execute: async (input) => {
|
|
553
|
+
try {
|
|
554
|
+
const projectId = getProjectId(config, input.project_id);
|
|
555
|
+
const model = await createStore(config, projectId).get();
|
|
556
|
+
if (!model) {
|
|
557
|
+
return createSuccessResult({
|
|
558
|
+
valid: false,
|
|
559
|
+
errors: [{ path: '', message: 'No Business Model found' }],
|
|
560
|
+
warnings: [],
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
const result = validateBusinessModel(model);
|
|
564
|
+
return createSuccessResult({
|
|
565
|
+
valid: result.valid,
|
|
566
|
+
errors: result.errors,
|
|
567
|
+
warnings: result.warnings,
|
|
568
|
+
revision: model.meta.revision,
|
|
569
|
+
});
|
|
570
|
+
}
|
|
571
|
+
catch (error) {
|
|
572
|
+
return createErrorResult(error instanceof Error ? error.message : String(error));
|
|
573
|
+
}
|
|
574
|
+
},
|
|
575
|
+
readonly: true,
|
|
576
|
+
});
|
|
577
|
+
}
|
|
578
|
+
// =============================================================================
|
|
579
|
+
// Public API
|
|
580
|
+
// =============================================================================
|
|
581
|
+
export function createBusinessModelTools(config) {
|
|
582
|
+
return [
|
|
583
|
+
createBizModelGetTool(config),
|
|
584
|
+
createBizModelUpdateTool(config),
|
|
585
|
+
createBizModelValidateTool(config),
|
|
586
|
+
];
|
|
587
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Business Model Types
|
|
3
|
+
*
|
|
4
|
+
* The Business Model describes a business: identity, value proposition,
|
|
5
|
+
* market, competitors, financials, and go-to-market strategy.
|
|
6
|
+
*/
|
|
7
|
+
export interface BusinessModel {
|
|
8
|
+
readonly identity: BusinessIdentity;
|
|
9
|
+
readonly valueProposition: ValueProposition;
|
|
10
|
+
readonly market: Market;
|
|
11
|
+
readonly competitors: readonly Competitor[];
|
|
12
|
+
readonly competitiveAdvantages?: readonly string[];
|
|
13
|
+
/** Positioning matrix: defines the 2 axes for competitive comparison */
|
|
14
|
+
readonly positioning?: PositioningMatrix;
|
|
15
|
+
readonly canvas: BusinessCanvas;
|
|
16
|
+
readonly financials: Financials;
|
|
17
|
+
readonly goToMarket: GoToMarket;
|
|
18
|
+
readonly team?: readonly TeamMember[];
|
|
19
|
+
readonly meta: BusinessMeta;
|
|
20
|
+
}
|
|
21
|
+
export type BusinessStage = 'idea' | 'pre-seed' | 'seed' | 'series-a' | 'growth' | 'established';
|
|
22
|
+
export interface BusinessIdentity {
|
|
23
|
+
readonly name: string;
|
|
24
|
+
readonly tagline?: string;
|
|
25
|
+
readonly mission?: string;
|
|
26
|
+
readonly stage: BusinessStage;
|
|
27
|
+
readonly industry?: string;
|
|
28
|
+
readonly sector?: string;
|
|
29
|
+
}
|
|
30
|
+
export interface ValueProposition {
|
|
31
|
+
readonly problem: string;
|
|
32
|
+
readonly solution: string;
|
|
33
|
+
readonly uniqueValue: string;
|
|
34
|
+
readonly targetCustomer?: string;
|
|
35
|
+
}
|
|
36
|
+
export interface MarketSize {
|
|
37
|
+
readonly value: string;
|
|
38
|
+
readonly description?: string;
|
|
39
|
+
readonly source?: string;
|
|
40
|
+
}
|
|
41
|
+
export interface CustomerSegment {
|
|
42
|
+
readonly id: string;
|
|
43
|
+
readonly name: string;
|
|
44
|
+
readonly description?: string;
|
|
45
|
+
readonly size?: string;
|
|
46
|
+
readonly painPoints?: readonly string[];
|
|
47
|
+
readonly willingness?: string;
|
|
48
|
+
}
|
|
49
|
+
export interface Market {
|
|
50
|
+
readonly tam?: MarketSize;
|
|
51
|
+
readonly sam?: MarketSize;
|
|
52
|
+
readonly som?: MarketSize;
|
|
53
|
+
readonly trends?: readonly string[];
|
|
54
|
+
readonly growthRate?: string;
|
|
55
|
+
readonly segments: readonly CustomerSegment[];
|
|
56
|
+
}
|
|
57
|
+
export type MarketPosition = 'leader' | 'challenger' | 'niche' | 'emerging';
|
|
58
|
+
export interface Competitor {
|
|
59
|
+
readonly id: string;
|
|
60
|
+
readonly name: string;
|
|
61
|
+
readonly description?: string;
|
|
62
|
+
readonly strengths: readonly string[];
|
|
63
|
+
readonly weaknesses: readonly string[];
|
|
64
|
+
readonly marketPosition?: MarketPosition;
|
|
65
|
+
readonly pricing?: string;
|
|
66
|
+
readonly url?: string;
|
|
67
|
+
/** Position on the 2D matrix (0-100 on each axis) */
|
|
68
|
+
readonly positionX?: number;
|
|
69
|
+
readonly positionY?: number;
|
|
70
|
+
}
|
|
71
|
+
export interface PositioningMatrix {
|
|
72
|
+
/** X-axis label (e.g., "Price", "Domain Specialization") */
|
|
73
|
+
readonly xAxis: string;
|
|
74
|
+
/** Y-axis label (e.g., "Features", "Multi-Agent Capability") */
|
|
75
|
+
readonly yAxis: string;
|
|
76
|
+
/** X-axis low end label (e.g., "Low", "General") */
|
|
77
|
+
readonly xLow?: string;
|
|
78
|
+
/** X-axis high end label (e.g., "High", "Specialized") */
|
|
79
|
+
readonly xHigh?: string;
|
|
80
|
+
/** Y-axis low end label */
|
|
81
|
+
readonly yLow?: string;
|
|
82
|
+
/** Y-axis high end label */
|
|
83
|
+
readonly yHigh?: string;
|
|
84
|
+
/** Your business position on X (0-100) */
|
|
85
|
+
readonly selfX: number;
|
|
86
|
+
/** Your business position on Y (0-100) */
|
|
87
|
+
readonly selfY: number;
|
|
88
|
+
}
|
|
89
|
+
export type RevenueType = 'subscription' | 'one-time' | 'usage' | 'advertising' | 'commission' | 'licensing' | 'other';
|
|
90
|
+
export interface RevenueStream {
|
|
91
|
+
readonly id: string;
|
|
92
|
+
readonly name: string;
|
|
93
|
+
readonly type: RevenueType;
|
|
94
|
+
readonly description?: string;
|
|
95
|
+
readonly projectedRevenue?: string;
|
|
96
|
+
}
|
|
97
|
+
export interface CostItem {
|
|
98
|
+
readonly id: string;
|
|
99
|
+
readonly category: 'fixed' | 'variable';
|
|
100
|
+
readonly name: string;
|
|
101
|
+
readonly amount?: string;
|
|
102
|
+
readonly frequency?: 'monthly' | 'yearly' | 'one-time';
|
|
103
|
+
}
|
|
104
|
+
export interface BusinessCanvas {
|
|
105
|
+
readonly revenueStreams: readonly RevenueStream[];
|
|
106
|
+
readonly costStructure: readonly CostItem[];
|
|
107
|
+
readonly keyResources?: readonly string[];
|
|
108
|
+
readonly keyActivities?: readonly string[];
|
|
109
|
+
readonly keyPartnerships?: readonly string[];
|
|
110
|
+
readonly channels?: readonly string[];
|
|
111
|
+
readonly customerRelationships?: readonly string[];
|
|
112
|
+
}
|
|
113
|
+
export interface ForecastEntry {
|
|
114
|
+
readonly period: string;
|
|
115
|
+
readonly category: string;
|
|
116
|
+
readonly amount: number;
|
|
117
|
+
readonly notes?: string;
|
|
118
|
+
}
|
|
119
|
+
export interface Financials {
|
|
120
|
+
readonly revenueForecasts: readonly ForecastEntry[];
|
|
121
|
+
readonly expenseForecasts: readonly ForecastEntry[];
|
|
122
|
+
readonly breakEvenPoint?: string;
|
|
123
|
+
readonly fundingNeeds?: string;
|
|
124
|
+
readonly useOfFunds?: string;
|
|
125
|
+
readonly assumptions?: readonly string[];
|
|
126
|
+
}
|
|
127
|
+
export interface GTMPhase {
|
|
128
|
+
readonly id: string;
|
|
129
|
+
readonly name: string;
|
|
130
|
+
readonly description?: string;
|
|
131
|
+
readonly targetDate?: string;
|
|
132
|
+
readonly milestones?: readonly string[];
|
|
133
|
+
}
|
|
134
|
+
export interface GoToMarket {
|
|
135
|
+
readonly strategy?: string;
|
|
136
|
+
readonly phases: readonly GTMPhase[];
|
|
137
|
+
readonly channels?: readonly string[];
|
|
138
|
+
readonly salesStrategy?: string;
|
|
139
|
+
}
|
|
140
|
+
export interface TeamMember {
|
|
141
|
+
readonly name: string;
|
|
142
|
+
readonly role: string;
|
|
143
|
+
readonly background?: string;
|
|
144
|
+
}
|
|
145
|
+
export interface BusinessMeta {
|
|
146
|
+
readonly revision: number;
|
|
147
|
+
readonly createdAt: string;
|
|
148
|
+
readonly updatedAt: string;
|
|
149
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -28,3 +28,5 @@ export { reactGoToolkit } from './toolkits/react-go/index.js';
|
|
|
28
28
|
export { factoryScaffoldSkill, factorySkills } from './factory/skill.js';
|
|
29
29
|
export type { ResearchModel, Section, SectionStatus, Claim, ClaimType, EvidenceStrength, SourceRef, Source, SourceRelevance, CitationInfo, CitationType, CitationStyle, ResearchQuestion, QuestionStatus, ResearchMeta, ResearchValidationError, ResearchValidationResult, ResearchModelOperation, ResearchModelToolsConfig, BibliographyOptions, BibTeXEntry, ResearchTemplate, ResearchTemplateFile, ResearchScaffoldConfig, } from './research-model/index.js';
|
|
30
30
|
export { createDefaultResearchModel, createDefaultSection, createDefaultClaim, createDefaultSource, createDefaultQuestion, ResearchModelStore, applyResearchOperation, validateResearchModel, createResearchModelTools, generateBibliography, parseBibTeX, RESEARCH_TEMPLATES, getResearchTemplate, apaPaperTemplate, ieeePaperTemplate, thesisTemplate, literatureReviewTemplate, labReportTemplate, createResearchScaffoldTool, } from './research-model/index.js';
|
|
31
|
+
export type { BusinessModel, BusinessIdentity, BusinessStage, ValueProposition, Market, MarketSize, CustomerSegment, Competitor, MarketPosition, BusinessCanvas, RevenueStream, RevenueType, CostItem, Financials, ForecastEntry, GoToMarket, GTMPhase, TeamMember, BusinessMeta, BusinessValidationError, BusinessValidationResult, BusinessModelToolsConfig, } from './business-model/index.js';
|
|
32
|
+
export { createDefaultBusinessModel, BusinessModelStore, validateBusinessModel, createBusinessModelTools, } from './business-model/index.js';
|
package/dist/index.js
CHANGED
|
@@ -34,3 +34,4 @@ export { reactGoToolkit } from './toolkits/react-go/index.js';
|
|
|
34
34
|
// Factory skill (Phase 5)
|
|
35
35
|
export { factoryScaffoldSkill, factorySkills } from './factory/skill.js';
|
|
36
36
|
export { createDefaultResearchModel, createDefaultSection, createDefaultClaim, createDefaultSource, createDefaultQuestion, ResearchModelStore, applyResearchOperation, validateResearchModel, createResearchModelTools, generateBibliography, parseBibTeX, RESEARCH_TEMPLATES, getResearchTemplate, apaPaperTemplate, ieeePaperTemplate, thesisTemplate, literatureReviewTemplate, labReportTemplate, createResearchScaffoldTool, } from './research-model/index.js';
|
|
37
|
+
export { createDefaultBusinessModel, BusinessModelStore, validateBusinessModel, createBusinessModelTools, } from './business-model/index.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@compilr-dev/factory",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.21",
|
|
4
4
|
"description": "AI-driven application scaffolder for the compilr-dev ecosystem",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -45,6 +45,6 @@
|
|
|
45
45
|
"code-generation"
|
|
46
46
|
],
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@compilr-dev/sdk": "^0.
|
|
48
|
+
"@compilr-dev/sdk": "^0.7.2"
|
|
49
49
|
}
|
|
50
50
|
}
|