@portel/photon 1.14.0 → 1.16.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/dist/auto-ui/beam/photon-management.d.ts +1 -1
- package/dist/auto-ui/beam/photon-management.d.ts.map +1 -1
- package/dist/auto-ui/beam/photon-management.js +5 -1
- package/dist/auto-ui/beam/photon-management.js.map +1 -1
- package/dist/auto-ui/beam/routes/api-config.d.ts.map +1 -1
- package/dist/auto-ui/beam/routes/api-config.js +31 -9
- package/dist/auto-ui/beam/routes/api-config.js.map +1 -1
- package/dist/auto-ui/beam/routes/api-marketplace.d.ts.map +1 -1
- package/dist/auto-ui/beam/routes/api-marketplace.js +3 -0
- package/dist/auto-ui/beam/routes/api-marketplace.js.map +1 -1
- package/dist/auto-ui/beam.d.ts.map +1 -1
- package/dist/auto-ui/beam.js +205 -56
- package/dist/auto-ui/beam.js.map +1 -1
- package/dist/auto-ui/bridge/index.d.ts.map +1 -1
- package/dist/auto-ui/bridge/index.js +578 -0
- package/dist/auto-ui/bridge/index.js.map +1 -1
- package/dist/auto-ui/bridge/renderers.d.ts.map +1 -1
- package/dist/auto-ui/bridge/renderers.js +7 -3
- package/dist/auto-ui/bridge/renderers.js.map +1 -1
- package/dist/auto-ui/bridge/types.d.ts +6 -0
- package/dist/auto-ui/bridge/types.d.ts.map +1 -1
- package/dist/auto-ui/frontend/pure-view.html +289 -0
- package/dist/auto-ui/photon-bridge.d.ts +11 -0
- package/dist/auto-ui/photon-bridge.d.ts.map +1 -1
- package/dist/auto-ui/photon-bridge.js +75 -1
- package/dist/auto-ui/photon-bridge.js.map +1 -1
- package/dist/auto-ui/streamable-http-transport.d.ts.map +1 -1
- package/dist/auto-ui/streamable-http-transport.js +29 -3
- package/dist/auto-ui/streamable-http-transport.js.map +1 -1
- package/dist/beam-form.bundle.js +5707 -0
- package/dist/beam-form.bundle.js.map +7 -0
- package/dist/beam.bundle.js +2863 -895
- package/dist/beam.bundle.js.map +4 -4
- package/dist/claude-code-plugin.js +11 -3
- package/dist/claude-code-plugin.js.map +1 -1
- package/dist/cli/commands/build.js +1 -1
- package/dist/cli/commands/build.js.map +1 -1
- package/dist/cli/commands/doctor.d.ts.map +1 -1
- package/dist/cli/commands/doctor.js +7 -5
- package/dist/cli/commands/doctor.js.map +1 -1
- package/dist/cli/commands/info.d.ts.map +1 -1
- package/dist/cli/commands/info.js +18 -4
- package/dist/cli/commands/info.js.map +1 -1
- package/dist/cli/commands/mcp.js +2 -2
- package/dist/cli/commands/mcp.js.map +1 -1
- package/dist/cli/commands/update.d.ts.map +1 -1
- package/dist/cli/commands/update.js +6 -2
- package/dist/cli/commands/update.js.map +1 -1
- package/dist/cli-alias.d.ts.map +1 -1
- package/dist/cli-alias.js +3 -2
- package/dist/cli-alias.js.map +1 -1
- package/dist/daemon/client.d.ts +5 -0
- package/dist/daemon/client.d.ts.map +1 -1
- package/dist/daemon/client.js +50 -0
- package/dist/daemon/client.js.map +1 -1
- package/dist/daemon/manager.d.ts +15 -0
- package/dist/daemon/manager.d.ts.map +1 -1
- package/dist/daemon/manager.js +142 -11
- package/dist/daemon/manager.js.map +1 -1
- package/dist/daemon/worker-manager.js +1 -1
- package/dist/daemon/worker-manager.js.map +1 -1
- package/dist/deploy/cloudflare.d.ts.map +1 -1
- package/dist/deploy/cloudflare.js +12 -10
- package/dist/deploy/cloudflare.js.map +1 -1
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +37 -2
- package/dist/loader.js.map +1 -1
- package/dist/marketplace-manager.d.ts +9 -0
- package/dist/marketplace-manager.d.ts.map +1 -1
- package/dist/marketplace-manager.js +115 -42
- package/dist/marketplace-manager.js.map +1 -1
- package/dist/meta.d.ts +51 -0
- package/dist/meta.d.ts.map +1 -0
- package/dist/meta.js +320 -0
- package/dist/meta.js.map +1 -0
- package/dist/photon-cli-runner.d.ts.map +1 -1
- package/dist/photon-cli-runner.js +30 -5
- package/dist/photon-cli-runner.js.map +1 -1
- package/dist/photon-doc-extractor.d.ts +1 -0
- package/dist/photon-doc-extractor.d.ts.map +1 -1
- package/dist/photon-doc-extractor.js +33 -21
- package/dist/photon-doc-extractor.js.map +1 -1
- package/dist/photons/builder-compass.photon.d.ts +167 -0
- package/dist/photons/builder-compass.photon.d.ts.map +1 -0
- package/dist/photons/builder-compass.photon.js +816 -0
- package/dist/photons/builder-compass.photon.js.map +1 -0
- package/dist/photons/builder-compass.photon.ts +1129 -0
- package/dist/photons/docs/ui/docs.html +441 -0
- package/dist/photons/docs.photon.d.ts +237 -0
- package/dist/photons/docs.photon.d.ts.map +1 -0
- package/dist/photons/docs.photon.js +483 -0
- package/dist/photons/docs.photon.js.map +1 -0
- package/dist/photons/docs.photon.ts +536 -0
- package/dist/photons/maker.photon.d.ts.map +1 -1
- package/dist/photons/maker.photon.js +19 -2
- package/dist/photons/maker.photon.js.map +1 -1
- package/dist/photons/maker.photon.ts +18 -2
- package/dist/photons/slides.photon.d.ts +212 -0
- package/dist/photons/slides.photon.d.ts.map +1 -0
- package/dist/photons/slides.photon.js +355 -0
- package/dist/photons/slides.photon.js.map +1 -0
- package/dist/photons/slides.photon.ts +370 -0
- package/dist/photons/spreadsheet/ui/spreadsheet.html +779 -0
- package/dist/photons/spreadsheet.photon.d.ts +554 -0
- package/dist/photons/spreadsheet.photon.d.ts.map +1 -0
- package/dist/photons/spreadsheet.photon.js +1050 -0
- package/dist/photons/spreadsheet.photon.js.map +1 -0
- package/dist/photons/spreadsheet.photon.ts +1239 -0
- package/dist/photons/ui/builder-compass.html +1199 -0
- package/dist/photons/ui/builder-compass.photon.html +380 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +33 -59
- package/dist/server.js.map +1 -1
- package/dist/shared/error-handler.d.ts +8 -0
- package/dist/shared/error-handler.d.ts.map +1 -1
- package/dist/shared/error-handler.js +50 -0
- package/dist/shared/error-handler.js.map +1 -1
- package/dist/shared-utils.d.ts +16 -2
- package/dist/shared-utils.d.ts.map +1 -1
- package/dist/shared-utils.js +37 -3
- package/dist/shared-utils.js.map +1 -1
- package/dist/template-manager.d.ts.map +1 -1
- package/dist/template-manager.js +2 -1
- package/dist/template-manager.js.map +1 -1
- package/package.json +8 -3
|
@@ -0,0 +1,1129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builder Compass
|
|
3
|
+
* @description Discover your strongest AI-native builder profile, research how people like you make money, and get an evidence-backed next-step roadmap.
|
|
4
|
+
* @icon 🧭
|
|
5
|
+
* @stateful
|
|
6
|
+
* @ui app ./ui/builder-compass.html
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
type ArchetypeTag =
|
|
10
|
+
| 'ai-augmented-solo-builder'
|
|
11
|
+
| 'agent-workflow-architect'
|
|
12
|
+
| 'developer-tools-builder'
|
|
13
|
+
| 'high-agency-integrator'
|
|
14
|
+
| 'implementation-consultant'
|
|
15
|
+
| 'product-technical-translator'
|
|
16
|
+
| 'prototype-driven-founder'
|
|
17
|
+
| 'systems-minded-operator';
|
|
18
|
+
|
|
19
|
+
type StrengthTag =
|
|
20
|
+
| 'ambiguity-tolerance'
|
|
21
|
+
| 'architecture'
|
|
22
|
+
| 'communication'
|
|
23
|
+
| 'curiosity'
|
|
24
|
+
| 'design-taste'
|
|
25
|
+
| 'distribution'
|
|
26
|
+
| 'execution'
|
|
27
|
+
| 'integration'
|
|
28
|
+
| 'judgment'
|
|
29
|
+
| 'product-intuition'
|
|
30
|
+
| 'rapid-prototyping'
|
|
31
|
+
| 'research'
|
|
32
|
+
| 'systems-thinking'
|
|
33
|
+
| 'workflow-design';
|
|
34
|
+
|
|
35
|
+
type WorkFitTag =
|
|
36
|
+
| 'ai-application-engineering'
|
|
37
|
+
| 'consulting'
|
|
38
|
+
| 'developer-tools'
|
|
39
|
+
| 'founder-path'
|
|
40
|
+
| 'hybrid-product-technical'
|
|
41
|
+
| 'implementation-work'
|
|
42
|
+
| 'indie-hacking'
|
|
43
|
+
| 'prototype-work'
|
|
44
|
+
| 'technical-education'
|
|
45
|
+
| 'workflow-automation';
|
|
46
|
+
|
|
47
|
+
type RiskTag =
|
|
48
|
+
| 'ai-overreliance'
|
|
49
|
+
| 'identity-diffusion'
|
|
50
|
+
| 'novelty-chasing'
|
|
51
|
+
| 'overextension'
|
|
52
|
+
| 'prestige-chasing'
|
|
53
|
+
| 'weak-finish-loops';
|
|
54
|
+
|
|
55
|
+
type MoneyModeTag =
|
|
56
|
+
| 'audience-plus-product'
|
|
57
|
+
| 'consulting-sprints'
|
|
58
|
+
| 'education-products'
|
|
59
|
+
| 'retainer-implementation'
|
|
60
|
+
| 'sell-tools'
|
|
61
|
+
| 'startup-wedge'
|
|
62
|
+
| 'template-productization';
|
|
63
|
+
|
|
64
|
+
interface LinkEvidence {
|
|
65
|
+
label: string;
|
|
66
|
+
url: string;
|
|
67
|
+
reason: string;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
interface ProfileInput {
|
|
71
|
+
name: string;
|
|
72
|
+
headline: string;
|
|
73
|
+
goalNow: string;
|
|
74
|
+
recentWork: string;
|
|
75
|
+
energizingWork: string;
|
|
76
|
+
constraints: string;
|
|
77
|
+
links: string[];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
interface BuilderProfile extends ProfileInput {
|
|
81
|
+
updatedAt: string;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
interface StrengthMatrixRow {
|
|
85
|
+
category: string;
|
|
86
|
+
score: number;
|
|
87
|
+
confidence: number;
|
|
88
|
+
energyFit: number;
|
|
89
|
+
strategicRelevance: number;
|
|
90
|
+
riskLoad: number;
|
|
91
|
+
rationale: string;
|
|
92
|
+
basis: 'natural aptitude' | 'learned competence' | 'aspirational identity';
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
interface IdentityAnalysis {
|
|
96
|
+
status: 'idle' | 'heuristic' | 'tinyfish';
|
|
97
|
+
title: string;
|
|
98
|
+
archetypeStatement: string;
|
|
99
|
+
identitySummary: string;
|
|
100
|
+
archetypeTags: ArchetypeTag[];
|
|
101
|
+
strengthTags: StrengthTag[];
|
|
102
|
+
workFitTags: WorkFitTag[];
|
|
103
|
+
riskTags: RiskTag[];
|
|
104
|
+
moneyModeTags: MoneyModeTag[];
|
|
105
|
+
strengthMatrix: StrengthMatrixRow[];
|
|
106
|
+
evidence: LinkEvidence[];
|
|
107
|
+
confidence: number;
|
|
108
|
+
lastUpdatedAt: string;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
interface MoneyPath {
|
|
112
|
+
title: string;
|
|
113
|
+
category: 'fastest-path' | 'compounding-path' | 'hybrid-path' | 'safe-path';
|
|
114
|
+
fitScore: number;
|
|
115
|
+
speedToMoney: number;
|
|
116
|
+
marketDemand: number;
|
|
117
|
+
sustainability: number;
|
|
118
|
+
executionDifficulty: number;
|
|
119
|
+
whyItFits: string;
|
|
120
|
+
examples: string[];
|
|
121
|
+
channels: string[];
|
|
122
|
+
firstSteps: string[];
|
|
123
|
+
risks: string[];
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
interface MarketResearch {
|
|
127
|
+
status: 'idle' | 'heuristic' | 'tinyfish';
|
|
128
|
+
researchSummary: string;
|
|
129
|
+
topPaths: MoneyPath[];
|
|
130
|
+
avoidPaths: string[];
|
|
131
|
+
nextMoves: string[];
|
|
132
|
+
evidence: LinkEvidence[];
|
|
133
|
+
lastUpdatedAt: string;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
interface CompassSnapshot {
|
|
137
|
+
productName: string;
|
|
138
|
+
profile: BuilderProfile;
|
|
139
|
+
identity: IdentityAnalysis;
|
|
140
|
+
market: MarketResearch;
|
|
141
|
+
apiKeyConfigured: boolean;
|
|
142
|
+
readyState: {
|
|
143
|
+
hasProfile: boolean;
|
|
144
|
+
hasIdentity: boolean;
|
|
145
|
+
hasMarket: boolean;
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
interface TinyFishRunResponse {
|
|
150
|
+
run_id?: string | null;
|
|
151
|
+
error?: { message?: string } | null;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export default class BuilderCompass {
|
|
155
|
+
tinyfishApiKey: string;
|
|
156
|
+
profile: BuilderProfile;
|
|
157
|
+
identity: IdentityAnalysis;
|
|
158
|
+
market: MarketResearch;
|
|
159
|
+
|
|
160
|
+
constructor() {
|
|
161
|
+
const now = new Date().toISOString();
|
|
162
|
+
this.tinyfishApiKey = '';
|
|
163
|
+
this.profile = {
|
|
164
|
+
name: '',
|
|
165
|
+
headline: '',
|
|
166
|
+
goalNow: '',
|
|
167
|
+
recentWork: '',
|
|
168
|
+
energizingWork: '',
|
|
169
|
+
constraints: '',
|
|
170
|
+
links: [],
|
|
171
|
+
updatedAt: now,
|
|
172
|
+
};
|
|
173
|
+
this.identity = this._blankIdentity(now);
|
|
174
|
+
this.market = this._blankMarket(now);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Open the Builder Compass dashboard
|
|
179
|
+
* @ui app
|
|
180
|
+
*/
|
|
181
|
+
async main(): Promise<CompassSnapshot> {
|
|
182
|
+
return this._snapshot();
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Save the builder profile and optional TinyFish API key
|
|
187
|
+
*/
|
|
188
|
+
async saveProfile(params: ProfileInput & { tinyfishApiKey?: string }): Promise<CompassSnapshot> {
|
|
189
|
+
const now = new Date().toISOString();
|
|
190
|
+
const nextProfile: BuilderProfile = {
|
|
191
|
+
name: params.name.trim(),
|
|
192
|
+
headline: params.headline.trim(),
|
|
193
|
+
goalNow: params.goalNow.trim(),
|
|
194
|
+
recentWork: params.recentWork.trim(),
|
|
195
|
+
energizingWork: params.energizingWork.trim(),
|
|
196
|
+
constraints: params.constraints.trim(),
|
|
197
|
+
links: (params.links || [])
|
|
198
|
+
.map((link) => link.trim())
|
|
199
|
+
.filter(Boolean)
|
|
200
|
+
.slice(0, 6),
|
|
201
|
+
updatedAt: now,
|
|
202
|
+
};
|
|
203
|
+
const previousComparable = JSON.stringify({
|
|
204
|
+
name: this.profile.name,
|
|
205
|
+
headline: this.profile.headline,
|
|
206
|
+
goalNow: this.profile.goalNow,
|
|
207
|
+
recentWork: this.profile.recentWork,
|
|
208
|
+
energizingWork: this.profile.energizingWork,
|
|
209
|
+
constraints: this.profile.constraints,
|
|
210
|
+
links: this.profile.links,
|
|
211
|
+
});
|
|
212
|
+
const nextComparable = JSON.stringify({
|
|
213
|
+
name: nextProfile.name,
|
|
214
|
+
headline: nextProfile.headline,
|
|
215
|
+
goalNow: nextProfile.goalNow,
|
|
216
|
+
recentWork: nextProfile.recentWork,
|
|
217
|
+
energizingWork: nextProfile.energizingWork,
|
|
218
|
+
constraints: nextProfile.constraints,
|
|
219
|
+
links: nextProfile.links,
|
|
220
|
+
});
|
|
221
|
+
const profileChanged = previousComparable !== nextComparable;
|
|
222
|
+
|
|
223
|
+
this.profile = nextProfile;
|
|
224
|
+
|
|
225
|
+
if (params.tinyfishApiKey && params.tinyfishApiKey.trim()) {
|
|
226
|
+
this.tinyfishApiKey = params.tinyfishApiKey.trim();
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (profileChanged) {
|
|
230
|
+
this.identity = {
|
|
231
|
+
...this._blankIdentity(now),
|
|
232
|
+
identitySummary:
|
|
233
|
+
'Profile updated. Re-run Builder Compass to refresh your archetype, strengths, and risks from the new input.',
|
|
234
|
+
};
|
|
235
|
+
this.market = {
|
|
236
|
+
...this._blankMarket(now),
|
|
237
|
+
researchSummary:
|
|
238
|
+
'Profile updated. Re-run market research to rebuild the money paths for the new builder profile.',
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return this._snapshot();
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Analyze the builder's identity, strengths, work fit, and risks
|
|
247
|
+
*/
|
|
248
|
+
async analyzeIdentity(): Promise<IdentityAnalysis> {
|
|
249
|
+
const now = new Date().toISOString();
|
|
250
|
+
this._ensureProfile();
|
|
251
|
+
|
|
252
|
+
let next = this._heuristicIdentity(now);
|
|
253
|
+
if (this._canUseTinyFish()) {
|
|
254
|
+
next = await this._tinyfishIdentity(now).catch(() => next);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
this.identity = next;
|
|
258
|
+
return this.identity;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Research how people with this profile are making money right now
|
|
263
|
+
*/
|
|
264
|
+
async researchMarket(): Promise<MarketResearch> {
|
|
265
|
+
const now = new Date().toISOString();
|
|
266
|
+
this._ensureProfile();
|
|
267
|
+
if (this.identity.status === 'idle') {
|
|
268
|
+
await this.analyzeIdentity();
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
let next = this._heuristicMarket(now);
|
|
272
|
+
if (this._canUseTinyFish()) {
|
|
273
|
+
next = await this._tinyfishMarket(now).catch(() => next);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
this.market = next;
|
|
277
|
+
return this.market;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Run the full builder compass flow end to end
|
|
282
|
+
*/
|
|
283
|
+
async runCompass(): Promise<CompassSnapshot> {
|
|
284
|
+
await this.analyzeIdentity();
|
|
285
|
+
await this.researchMarket();
|
|
286
|
+
return this._snapshot();
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Structured strengths matrix for agents and dashboards
|
|
291
|
+
* @format table
|
|
292
|
+
*/
|
|
293
|
+
async strengthMatrix(): Promise<Array<Record<string, string | number>>> {
|
|
294
|
+
if (this.identity.status === 'idle') {
|
|
295
|
+
await this.analyzeIdentity();
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
return this.identity.strengthMatrix.map((row) => ({
|
|
299
|
+
category: row.category,
|
|
300
|
+
score: row.score,
|
|
301
|
+
confidence: row.confidence,
|
|
302
|
+
energy_fit: row.energyFit,
|
|
303
|
+
strategic_relevance: row.strategicRelevance,
|
|
304
|
+
risk_load: row.riskLoad,
|
|
305
|
+
basis: row.basis,
|
|
306
|
+
rationale: row.rationale,
|
|
307
|
+
}));
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Ranked money paths for this builder profile
|
|
312
|
+
* @format table
|
|
313
|
+
*/
|
|
314
|
+
async moneyPaths(): Promise<Array<Record<string, string | number>>> {
|
|
315
|
+
if (this.market.status === 'idle') {
|
|
316
|
+
await this.researchMarket();
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
return this.market.topPaths.map((path) => ({
|
|
320
|
+
title: path.title,
|
|
321
|
+
category: path.category,
|
|
322
|
+
fit_score: path.fitScore,
|
|
323
|
+
speed_to_money: path.speedToMoney,
|
|
324
|
+
market_demand: path.marketDemand,
|
|
325
|
+
sustainability: path.sustainability,
|
|
326
|
+
execution_difficulty: path.executionDifficulty,
|
|
327
|
+
why_it_fits: path.whyItFits,
|
|
328
|
+
}));
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Quick visual fit panel for the dashboard
|
|
333
|
+
* @format panels
|
|
334
|
+
*/
|
|
335
|
+
async fitOverview(): Promise<Array<{ label: string; value: number; note: string }>> {
|
|
336
|
+
if (this.identity.status === 'idle') {
|
|
337
|
+
await this.analyzeIdentity();
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
const getAverage = (keys: StrengthTag[]) => {
|
|
341
|
+
const rows = this.identity.strengthMatrix.filter((row) =>
|
|
342
|
+
keys.some((key) => row.category.toLowerCase().replace(/ /g, '-') === key)
|
|
343
|
+
);
|
|
344
|
+
if (rows.length === 0) return 0.5;
|
|
345
|
+
return Number((rows.reduce((sum, row) => sum + row.score, 0) / rows.length).toFixed(2));
|
|
346
|
+
};
|
|
347
|
+
|
|
348
|
+
return [
|
|
349
|
+
{
|
|
350
|
+
label: 'AI-native leverage',
|
|
351
|
+
value: getAverage(['rapid-prototyping', 'workflow-design', 'integration']),
|
|
352
|
+
note: 'How naturally you seem to use agents and automation as force multipliers.',
|
|
353
|
+
},
|
|
354
|
+
{
|
|
355
|
+
label: 'Founder energy',
|
|
356
|
+
value: getAverage(['product-intuition', 'judgment', 'communication']),
|
|
357
|
+
note: 'Your appetite for ownership, wedge selection, and shipping toward market outcomes.',
|
|
358
|
+
},
|
|
359
|
+
{
|
|
360
|
+
label: 'Execution reliability',
|
|
361
|
+
value: getAverage(['execution', 'architecture', 'systems-thinking']),
|
|
362
|
+
note: 'Whether your ideas are likely to hold together once translated into work.',
|
|
363
|
+
},
|
|
364
|
+
{
|
|
365
|
+
label: 'Risk load',
|
|
366
|
+
value: Number(
|
|
367
|
+
(
|
|
368
|
+
this.identity.strengthMatrix.reduce((sum, row) => sum + row.riskLoad, 0) /
|
|
369
|
+
this.identity.strengthMatrix.length
|
|
370
|
+
).toFixed(2)
|
|
371
|
+
),
|
|
372
|
+
note: 'Higher means more pressure from distraction, inconsistency, or overextension.',
|
|
373
|
+
},
|
|
374
|
+
];
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* Full narrative guide for the user
|
|
379
|
+
* @format markdown
|
|
380
|
+
*/
|
|
381
|
+
async report(): Promise<string> {
|
|
382
|
+
if (this.market.status === 'idle') {
|
|
383
|
+
await this.runCompass();
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
const top = this.market.topPaths[0];
|
|
387
|
+
return [
|
|
388
|
+
`# Builder Compass for ${this.profile.name || 'this builder'}`,
|
|
389
|
+
'',
|
|
390
|
+
`## Identity snapshot`,
|
|
391
|
+
'',
|
|
392
|
+
`**Archetype:** ${this.identity.title}`,
|
|
393
|
+
'',
|
|
394
|
+
this.identity.identitySummary,
|
|
395
|
+
'',
|
|
396
|
+
`### Strongest profile tags`,
|
|
397
|
+
'',
|
|
398
|
+
...this.identity.archetypeTags.map((tag) => `- ${this._labelize(tag)}`),
|
|
399
|
+
'',
|
|
400
|
+
`### Best immediate money path`,
|
|
401
|
+
'',
|
|
402
|
+
`**${top?.title || 'No path scored yet'}**`,
|
|
403
|
+
'',
|
|
404
|
+
top ? top.whyItFits : 'Run market research to score the best routes.',
|
|
405
|
+
'',
|
|
406
|
+
`### Recommended next moves`,
|
|
407
|
+
'',
|
|
408
|
+
...this.market.nextMoves.map((step) => `- ${step}`),
|
|
409
|
+
'',
|
|
410
|
+
`### Paths to avoid`,
|
|
411
|
+
'',
|
|
412
|
+
...this.market.avoidPaths.map((path) => `- ${path}`),
|
|
413
|
+
].join('\n');
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
private _snapshot(): CompassSnapshot {
|
|
417
|
+
return {
|
|
418
|
+
productName: 'Builder Compass',
|
|
419
|
+
profile: structuredClone(this.profile),
|
|
420
|
+
identity: structuredClone(this.identity),
|
|
421
|
+
market: structuredClone(this.market),
|
|
422
|
+
apiKeyConfigured: this._canUseTinyFish(),
|
|
423
|
+
readyState: {
|
|
424
|
+
hasProfile: Boolean(this.profile.goalNow || this.profile.recentWork || this.profile.energizingWork),
|
|
425
|
+
hasIdentity: this.identity.status !== 'idle',
|
|
426
|
+
hasMarket: this.market.status !== 'idle',
|
|
427
|
+
},
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
private _blankIdentity(now: string): IdentityAnalysis {
|
|
432
|
+
return {
|
|
433
|
+
status: 'idle',
|
|
434
|
+
title: 'Awaiting profile',
|
|
435
|
+
archetypeStatement: '',
|
|
436
|
+
identitySummary: 'Add your profile so Builder Compass can classify your builder archetype.',
|
|
437
|
+
archetypeTags: [],
|
|
438
|
+
strengthTags: [],
|
|
439
|
+
workFitTags: [],
|
|
440
|
+
riskTags: [],
|
|
441
|
+
moneyModeTags: [],
|
|
442
|
+
strengthMatrix: [],
|
|
443
|
+
evidence: [],
|
|
444
|
+
confidence: 0,
|
|
445
|
+
lastUpdatedAt: now,
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
private _blankMarket(now: string): MarketResearch {
|
|
450
|
+
return {
|
|
451
|
+
status: 'idle',
|
|
452
|
+
researchSummary: 'No market research has been run yet.',
|
|
453
|
+
topPaths: [],
|
|
454
|
+
avoidPaths: [],
|
|
455
|
+
nextMoves: [],
|
|
456
|
+
evidence: [],
|
|
457
|
+
lastUpdatedAt: now,
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
private _ensureProfile(): void {
|
|
462
|
+
if (!this.profile.goalNow && !this.profile.recentWork && !this.profile.energizingWork) {
|
|
463
|
+
throw new Error('Save a profile first.');
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
private _canUseTinyFish(): boolean {
|
|
468
|
+
return Boolean(this.tinyfishApiKey);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
private _heuristicIdentity(now: string): IdentityAnalysis {
|
|
472
|
+
const corpus = `${this.profile.headline} ${this.profile.goalNow} ${this.profile.recentWork} ${this.profile.energizingWork} ${this.profile.constraints}`.toLowerCase();
|
|
473
|
+
const strengthTags = new Set<StrengthTag>(['systems-thinking', 'curiosity']);
|
|
474
|
+
const workFitTags = new Set<WorkFitTag>(['workflow-automation', 'prototype-work']);
|
|
475
|
+
const riskTags = new Set<RiskTag>();
|
|
476
|
+
const moneyModeTags = new Set<MoneyModeTag>(['consulting-sprints']);
|
|
477
|
+
const archetypeTags = new Set<ArchetypeTag>();
|
|
478
|
+
const evidence: LinkEvidence[] = [];
|
|
479
|
+
|
|
480
|
+
const addIf = <T>(condition: boolean, target: Set<T>, value: T) => {
|
|
481
|
+
if (condition) target.add(value);
|
|
482
|
+
};
|
|
483
|
+
|
|
484
|
+
addIf(/agent|automation|mcp|workflow/.test(corpus), strengthTags, 'workflow-design');
|
|
485
|
+
addIf(/agent|automation|mcp|workflow/.test(corpus), workFitTags, 'workflow-automation');
|
|
486
|
+
addIf(/agent|automation|mcp|workflow/.test(corpus), archetypeTags, 'agent-workflow-architect');
|
|
487
|
+
|
|
488
|
+
addIf(/product|user|wedge|market|pmf/.test(corpus), strengthTags, 'product-intuition');
|
|
489
|
+
addIf(/product|user|wedge|market|pmf/.test(corpus), workFitTags, 'hybrid-product-technical');
|
|
490
|
+
addIf(/product|user|wedge|market|pmf/.test(corpus), archetypeTags, 'product-technical-translator');
|
|
491
|
+
|
|
492
|
+
addIf(/prototype|ship|hackathon|fast|quick/.test(corpus), strengthTags, 'rapid-prototyping');
|
|
493
|
+
addIf(/prototype|ship|hackathon|fast|quick/.test(corpus), archetypeTags, 'ai-augmented-solo-builder');
|
|
494
|
+
addIf(/prototype|ship|hackathon|fast|quick/.test(corpus), moneyModeTags, 'template-productization');
|
|
495
|
+
|
|
496
|
+
addIf(/consult|client|implementation|service/.test(corpus), archetypeTags, 'implementation-consultant');
|
|
497
|
+
addIf(/consult|client|implementation|service/.test(corpus), workFitTags, 'consulting');
|
|
498
|
+
addIf(/consult|client|implementation|service/.test(corpus), moneyModeTags, 'retainer-implementation');
|
|
499
|
+
|
|
500
|
+
addIf(/tool|developer|sdk|runtime|platform|photon/.test(corpus), archetypeTags, 'developer-tools-builder');
|
|
501
|
+
addIf(/tool|developer|sdk|runtime|platform|photon/.test(corpus), workFitTags, 'developer-tools');
|
|
502
|
+
addIf(/tool|developer|sdk|runtime|platform|photon/.test(corpus), moneyModeTags, 'sell-tools');
|
|
503
|
+
|
|
504
|
+
addIf(/founder|startup|business|revenue|income/.test(corpus), archetypeTags, 'prototype-driven-founder');
|
|
505
|
+
addIf(/founder|startup|business|revenue|income/.test(corpus), workFitTags, 'founder-path');
|
|
506
|
+
addIf(/founder|startup|business|revenue|income/.test(corpus), moneyModeTags, 'startup-wedge');
|
|
507
|
+
|
|
508
|
+
addIf(/teach|write|guide|community|explain/.test(corpus), strengthTags, 'communication');
|
|
509
|
+
addIf(/teach|write|guide|community|explain/.test(corpus), workFitTags, 'technical-education');
|
|
510
|
+
addIf(/teach|write|guide|community|explain/.test(corpus), moneyModeTags, 'education-products');
|
|
511
|
+
|
|
512
|
+
addIf(/design|taste|ui|ux/.test(corpus), strengthTags, 'design-taste');
|
|
513
|
+
addIf(/research|deep|analyze/.test(corpus), strengthTags, 'research');
|
|
514
|
+
addIf(/integrate|connect|bridge/.test(corpus), strengthTags, 'integration');
|
|
515
|
+
addIf(/architect|system|infra/.test(corpus), strengthTags, 'architecture');
|
|
516
|
+
addIf(/market|distribution|audience/.test(corpus), strengthTags, 'distribution');
|
|
517
|
+
addIf(/judgment|decide|strategy/.test(corpus), strengthTags, 'judgment');
|
|
518
|
+
addIf(/execute|finish|ship/.test(corpus), strengthTags, 'execution');
|
|
519
|
+
|
|
520
|
+
addIf(/too many|many ideas|scatter|different directions/.test(corpus), riskTags, 'identity-diffusion');
|
|
521
|
+
addIf(/urgent|fast|many things|stretch/.test(corpus), riskTags, 'overextension');
|
|
522
|
+
addIf(/new|explore|different ideas|possibilities/.test(corpus), riskTags, 'novelty-chasing');
|
|
523
|
+
|
|
524
|
+
if (this.profile.links.some((link) => link.includes('github.com'))) {
|
|
525
|
+
strengthTags.add('execution');
|
|
526
|
+
evidence.push({
|
|
527
|
+
label: 'GitHub',
|
|
528
|
+
url: this.profile.links.find((link) => link.includes('github.com')) || '',
|
|
529
|
+
reason: 'Public repositories suggest real shipping behavior, not only aspiration.',
|
|
530
|
+
});
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
if (this.profile.links.some((link) => link.includes('linkedin.com'))) {
|
|
534
|
+
evidence.push({
|
|
535
|
+
label: 'LinkedIn',
|
|
536
|
+
url: this.profile.links.find((link) => link.includes('linkedin.com')) || '',
|
|
537
|
+
reason: 'Professional profile helps ground role and credibility context.',
|
|
538
|
+
});
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
const title =
|
|
542
|
+
archetypeTags.has('prototype-driven-founder')
|
|
543
|
+
? 'Prototype-driven founder with systems instincts'
|
|
544
|
+
: archetypeTags.has('implementation-consultant')
|
|
545
|
+
? 'High-agency implementation consultant in the making'
|
|
546
|
+
: archetypeTags.has('developer-tools-builder')
|
|
547
|
+
? 'Developer-tools builder with AI-native leverage'
|
|
548
|
+
: 'AI-augmented product-technical builder';
|
|
549
|
+
|
|
550
|
+
const strengthMatrix = this._buildStrengthMatrix(
|
|
551
|
+
Array.from(strengthTags),
|
|
552
|
+
Array.from(riskTags),
|
|
553
|
+
Array.from(workFitTags)
|
|
554
|
+
);
|
|
555
|
+
|
|
556
|
+
return {
|
|
557
|
+
status: 'heuristic',
|
|
558
|
+
title,
|
|
559
|
+
archetypeStatement: title,
|
|
560
|
+
identitySummary:
|
|
561
|
+
`Based on your profile, you look most aligned with ${Array.from(archetypeTags).map((tag) => this._labelize(tag).toLowerCase()).join(', ')} work. ` +
|
|
562
|
+
`The strongest repeatable signals point toward ${Array.from(strengthTags).slice(0, 4).map((tag) => this._labelize(tag).toLowerCase()).join(', ')}.`,
|
|
563
|
+
archetypeTags: this._dedupe(
|
|
564
|
+
Array.from(archetypeTags).length > 0
|
|
565
|
+
? Array.from(archetypeTags)
|
|
566
|
+
: ['product-technical-translator', 'ai-augmented-solo-builder']
|
|
567
|
+
),
|
|
568
|
+
strengthTags: this._dedupe(Array.from(strengthTags)),
|
|
569
|
+
workFitTags: this._dedupe(Array.from(workFitTags)),
|
|
570
|
+
riskTags: this._dedupe(Array.from(riskTags.size ? Array.from(riskTags) : ['weak-finish-loops'])),
|
|
571
|
+
moneyModeTags: this._dedupe(
|
|
572
|
+
Array.from(moneyModeTags).length > 0
|
|
573
|
+
? Array.from(moneyModeTags)
|
|
574
|
+
: ['consulting-sprints', 'template-productization']
|
|
575
|
+
),
|
|
576
|
+
strengthMatrix,
|
|
577
|
+
evidence,
|
|
578
|
+
confidence: 0.71,
|
|
579
|
+
lastUpdatedAt: now,
|
|
580
|
+
};
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
private _heuristicMarket(now: string): MarketResearch {
|
|
584
|
+
const workFit = new Set(this.identity.workFitTags);
|
|
585
|
+
const moneyModes = new Set(this.identity.moneyModeTags);
|
|
586
|
+
const paths: MoneyPath[] = [];
|
|
587
|
+
|
|
588
|
+
const pushPath = (path: MoneyPath) => paths.push(path);
|
|
589
|
+
|
|
590
|
+
if (workFit.has('consulting') || moneyModes.has('retainer-implementation')) {
|
|
591
|
+
pushPath({
|
|
592
|
+
title: 'Agent workflow implementation sprints',
|
|
593
|
+
category: 'fastest-path',
|
|
594
|
+
fitScore: 0.89,
|
|
595
|
+
speedToMoney: 0.92,
|
|
596
|
+
marketDemand: 0.78,
|
|
597
|
+
sustainability: 0.71,
|
|
598
|
+
executionDifficulty: 0.46,
|
|
599
|
+
whyItFits:
|
|
600
|
+
'This turns builder skill and systems taste into fast, scoped revenue without waiting for product traction.',
|
|
601
|
+
examples: ['MCP integrations', 'internal workflow copilots', 'automation audits'],
|
|
602
|
+
channels: ['X / LinkedIn build-in-public', 'warm intros', 'founder communities'],
|
|
603
|
+
firstSteps: ['Package 2-3 fixed offers', 'Publish one sharp case study', 'Offer a 1-week sprint'],
|
|
604
|
+
risks: ['Custom work can sprawl', 'Need tight scope control'],
|
|
605
|
+
});
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
if (workFit.has('developer-tools') || moneyModes.has('sell-tools')) {
|
|
609
|
+
pushPath({
|
|
610
|
+
title: 'Niche developer tool with audience-led distribution',
|
|
611
|
+
category: 'compounding-path',
|
|
612
|
+
fitScore: 0.83,
|
|
613
|
+
speedToMoney: 0.49,
|
|
614
|
+
marketDemand: 0.75,
|
|
615
|
+
sustainability: 0.88,
|
|
616
|
+
executionDifficulty: 0.67,
|
|
617
|
+
whyItFits:
|
|
618
|
+
'A focused tool aligns with technical credibility and compounds into durable reputation if the wedge is sharp.',
|
|
619
|
+
examples: ['Photon add-ons', 'agent debugging tools', 'workflow visibility tooling'],
|
|
620
|
+
channels: ['GitHub', 'dev communities', 'technical writing'],
|
|
621
|
+
firstSteps: ['Pick one painful wedge', 'Ship a public MVP', 'Collect 5 users before broadening'],
|
|
622
|
+
risks: ['Slow monetization if positioning is vague', 'Can become hobbyware'],
|
|
623
|
+
});
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
if (workFit.has('technical-education') || moneyModes.has('education-products')) {
|
|
627
|
+
pushPath({
|
|
628
|
+
title: 'Teach through implementation assets',
|
|
629
|
+
category: 'hybrid-path',
|
|
630
|
+
fitScore: 0.74,
|
|
631
|
+
speedToMoney: 0.63,
|
|
632
|
+
marketDemand: 0.66,
|
|
633
|
+
sustainability: 0.72,
|
|
634
|
+
executionDifficulty: 0.44,
|
|
635
|
+
whyItFits:
|
|
636
|
+
'If your edge includes explanation and synthesis, templates, teardown guides, or workshops can monetize quickly.',
|
|
637
|
+
examples: ['Agent workflow teardown packs', 'builder strategy playbooks', 'implementation workshops'],
|
|
638
|
+
channels: ['Newsletter', 'creator platforms', 'cohort communities'],
|
|
639
|
+
firstSteps: ['Package one repeatable lesson', 'Turn a real project into a case study', 'Sell a small paid asset first'],
|
|
640
|
+
risks: ['Can drift into content without moat', 'Needs specificity to convert'],
|
|
641
|
+
});
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
pushPath({
|
|
645
|
+
title: 'Hybrid builder-consultant path',
|
|
646
|
+
category: 'safe-path',
|
|
647
|
+
fitScore: 0.81,
|
|
648
|
+
speedToMoney: 0.78,
|
|
649
|
+
marketDemand: 0.74,
|
|
650
|
+
sustainability: 0.79,
|
|
651
|
+
executionDifficulty: 0.51,
|
|
652
|
+
whyItFits:
|
|
653
|
+
'Combining small consulting revenue with one compounding product lets you de-risk experimentation without losing upside.',
|
|
654
|
+
examples: ['Paid implementation plus internal tooling', 'Consulting funded product wedge'],
|
|
655
|
+
channels: ['Warm network', 'public prototypes', 'operator communities'],
|
|
656
|
+
firstSteps: ['Choose one service and one product wedge', 'Set weekly split', 'Avoid building three products at once'],
|
|
657
|
+
risks: ['Context switching', 'Product never gets enough depth'],
|
|
658
|
+
});
|
|
659
|
+
|
|
660
|
+
const topPaths = paths.sort((a, b) => b.fitScore - a.fitScore);
|
|
661
|
+
|
|
662
|
+
return {
|
|
663
|
+
status: 'heuristic',
|
|
664
|
+
researchSummary:
|
|
665
|
+
'Builder Compass combined your inferred archetype with common monetization patterns for AI-native builders. The highest-probability routes favor speed-to-proof, then compounding assets.',
|
|
666
|
+
topPaths,
|
|
667
|
+
avoidPaths: [
|
|
668
|
+
'Generic “AI agency” positioning with no niche',
|
|
669
|
+
'Long product build with no user validation',
|
|
670
|
+
'Prestige roles that remove autonomy and product ownership',
|
|
671
|
+
],
|
|
672
|
+
nextMoves: [
|
|
673
|
+
'Choose one money path to test for the next 30 days.',
|
|
674
|
+
'Turn one real project into a public proof asset.',
|
|
675
|
+
'Use outreach or content to validate demand before broadening the offer.',
|
|
676
|
+
],
|
|
677
|
+
evidence: [
|
|
678
|
+
{
|
|
679
|
+
label: 'Profile-model synthesis',
|
|
680
|
+
url: this.profile.links[0] || 'local://profile',
|
|
681
|
+
reason: 'Your current profile suggests hybrid builder + strategy value rather than pure commodity implementation.',
|
|
682
|
+
},
|
|
683
|
+
],
|
|
684
|
+
lastUpdatedAt: now,
|
|
685
|
+
};
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
private async _tinyfishIdentity(now: string): Promise<IdentityAnalysis> {
|
|
689
|
+
const searchPrompt = [
|
|
690
|
+
`You are classifying an AI-native builder.`,
|
|
691
|
+
`Research the person using the provided links and profile details.`,
|
|
692
|
+
`Return STRICT JSON with keys: title, identitySummary, archetypeTags, strengthTags, workFitTags, riskTags, moneyModeTags, evidence.`,
|
|
693
|
+
`Allowed archetype tags: ${this._allTags<ArchetypeTag>([
|
|
694
|
+
'ai-augmented-solo-builder',
|
|
695
|
+
'agent-workflow-architect',
|
|
696
|
+
'developer-tools-builder',
|
|
697
|
+
'high-agency-integrator',
|
|
698
|
+
'implementation-consultant',
|
|
699
|
+
'product-technical-translator',
|
|
700
|
+
'prototype-driven-founder',
|
|
701
|
+
'systems-minded-operator',
|
|
702
|
+
])}.`,
|
|
703
|
+
`Allowed strength tags: ${this._allTags<StrengthTag>([
|
|
704
|
+
'ambiguity-tolerance',
|
|
705
|
+
'architecture',
|
|
706
|
+
'communication',
|
|
707
|
+
'curiosity',
|
|
708
|
+
'design-taste',
|
|
709
|
+
'distribution',
|
|
710
|
+
'execution',
|
|
711
|
+
'integration',
|
|
712
|
+
'judgment',
|
|
713
|
+
'product-intuition',
|
|
714
|
+
'rapid-prototyping',
|
|
715
|
+
'research',
|
|
716
|
+
'systems-thinking',
|
|
717
|
+
'workflow-design',
|
|
718
|
+
])}.`,
|
|
719
|
+
`Allowed work fit tags: ${this._allTags<WorkFitTag>([
|
|
720
|
+
'ai-application-engineering',
|
|
721
|
+
'consulting',
|
|
722
|
+
'developer-tools',
|
|
723
|
+
'founder-path',
|
|
724
|
+
'hybrid-product-technical',
|
|
725
|
+
'implementation-work',
|
|
726
|
+
'indie-hacking',
|
|
727
|
+
'prototype-work',
|
|
728
|
+
'technical-education',
|
|
729
|
+
'workflow-automation',
|
|
730
|
+
])}.`,
|
|
731
|
+
`Allowed risk tags: ${this._allTags<RiskTag>([
|
|
732
|
+
'ai-overreliance',
|
|
733
|
+
'identity-diffusion',
|
|
734
|
+
'novelty-chasing',
|
|
735
|
+
'overextension',
|
|
736
|
+
'prestige-chasing',
|
|
737
|
+
'weak-finish-loops',
|
|
738
|
+
])}.`,
|
|
739
|
+
`Allowed money mode tags: ${this._allTags<MoneyModeTag>([
|
|
740
|
+
'audience-plus-product',
|
|
741
|
+
'consulting-sprints',
|
|
742
|
+
'education-products',
|
|
743
|
+
'retainer-implementation',
|
|
744
|
+
'sell-tools',
|
|
745
|
+
'startup-wedge',
|
|
746
|
+
'template-productization',
|
|
747
|
+
])}.`,
|
|
748
|
+
`Builder name: ${this.profile.name}`,
|
|
749
|
+
`Headline: ${this.profile.headline}`,
|
|
750
|
+
`Goal now: ${this.profile.goalNow}`,
|
|
751
|
+
`Recent work: ${this.profile.recentWork}`,
|
|
752
|
+
`Energizing work: ${this.profile.energizingWork}`,
|
|
753
|
+
`Constraints: ${this.profile.constraints}`,
|
|
754
|
+
`Links: ${this.profile.links.join(', ') || 'none'}`,
|
|
755
|
+
].join('\n');
|
|
756
|
+
|
|
757
|
+
const parsed = await this._runTinyFishSearch(searchPrompt);
|
|
758
|
+
return {
|
|
759
|
+
...this._heuristicIdentity(now),
|
|
760
|
+
status: 'tinyfish',
|
|
761
|
+
title: String(parsed.title || 'TinyFish builder profile'),
|
|
762
|
+
identitySummary: String(parsed.identitySummary || 'TinyFish returned a builder profile summary.'),
|
|
763
|
+
archetypeTags: this._filterAllowed<ArchetypeTag>(parsed.archetypeTags, [
|
|
764
|
+
'ai-augmented-solo-builder',
|
|
765
|
+
'agent-workflow-architect',
|
|
766
|
+
'developer-tools-builder',
|
|
767
|
+
'high-agency-integrator',
|
|
768
|
+
'implementation-consultant',
|
|
769
|
+
'product-technical-translator',
|
|
770
|
+
'prototype-driven-founder',
|
|
771
|
+
'systems-minded-operator',
|
|
772
|
+
]),
|
|
773
|
+
strengthTags: this._filterAllowed<StrengthTag>(parsed.strengthTags, [
|
|
774
|
+
'ambiguity-tolerance',
|
|
775
|
+
'architecture',
|
|
776
|
+
'communication',
|
|
777
|
+
'curiosity',
|
|
778
|
+
'design-taste',
|
|
779
|
+
'distribution',
|
|
780
|
+
'execution',
|
|
781
|
+
'integration',
|
|
782
|
+
'judgment',
|
|
783
|
+
'product-intuition',
|
|
784
|
+
'rapid-prototyping',
|
|
785
|
+
'research',
|
|
786
|
+
'systems-thinking',
|
|
787
|
+
'workflow-design',
|
|
788
|
+
]),
|
|
789
|
+
workFitTags: this._filterAllowed<WorkFitTag>(parsed.workFitTags, [
|
|
790
|
+
'ai-application-engineering',
|
|
791
|
+
'consulting',
|
|
792
|
+
'developer-tools',
|
|
793
|
+
'founder-path',
|
|
794
|
+
'hybrid-product-technical',
|
|
795
|
+
'implementation-work',
|
|
796
|
+
'indie-hacking',
|
|
797
|
+
'prototype-work',
|
|
798
|
+
'technical-education',
|
|
799
|
+
'workflow-automation',
|
|
800
|
+
]),
|
|
801
|
+
riskTags: this._filterAllowed<RiskTag>(parsed.riskTags, [
|
|
802
|
+
'ai-overreliance',
|
|
803
|
+
'identity-diffusion',
|
|
804
|
+
'novelty-chasing',
|
|
805
|
+
'overextension',
|
|
806
|
+
'prestige-chasing',
|
|
807
|
+
'weak-finish-loops',
|
|
808
|
+
]),
|
|
809
|
+
moneyModeTags: this._filterAllowed<MoneyModeTag>(parsed.moneyModeTags, [
|
|
810
|
+
'audience-plus-product',
|
|
811
|
+
'consulting-sprints',
|
|
812
|
+
'education-products',
|
|
813
|
+
'retainer-implementation',
|
|
814
|
+
'sell-tools',
|
|
815
|
+
'startup-wedge',
|
|
816
|
+
'template-productization',
|
|
817
|
+
]),
|
|
818
|
+
evidence: this._normalizeEvidence(parsed.evidence),
|
|
819
|
+
strengthMatrix: this._buildStrengthMatrix(
|
|
820
|
+
this._filterAllowed<StrengthTag>(parsed.strengthTags, [
|
|
821
|
+
'ambiguity-tolerance',
|
|
822
|
+
'architecture',
|
|
823
|
+
'communication',
|
|
824
|
+
'curiosity',
|
|
825
|
+
'design-taste',
|
|
826
|
+
'distribution',
|
|
827
|
+
'execution',
|
|
828
|
+
'integration',
|
|
829
|
+
'judgment',
|
|
830
|
+
'product-intuition',
|
|
831
|
+
'rapid-prototyping',
|
|
832
|
+
'research',
|
|
833
|
+
'systems-thinking',
|
|
834
|
+
'workflow-design',
|
|
835
|
+
]),
|
|
836
|
+
this._filterAllowed<RiskTag>(parsed.riskTags, [
|
|
837
|
+
'ai-overreliance',
|
|
838
|
+
'identity-diffusion',
|
|
839
|
+
'novelty-chasing',
|
|
840
|
+
'overextension',
|
|
841
|
+
'prestige-chasing',
|
|
842
|
+
'weak-finish-loops',
|
|
843
|
+
]),
|
|
844
|
+
this._filterAllowed<WorkFitTag>(parsed.workFitTags, [
|
|
845
|
+
'ai-application-engineering',
|
|
846
|
+
'consulting',
|
|
847
|
+
'developer-tools',
|
|
848
|
+
'founder-path',
|
|
849
|
+
'hybrid-product-technical',
|
|
850
|
+
'implementation-work',
|
|
851
|
+
'indie-hacking',
|
|
852
|
+
'prototype-work',
|
|
853
|
+
'technical-education',
|
|
854
|
+
'workflow-automation',
|
|
855
|
+
])
|
|
856
|
+
),
|
|
857
|
+
confidence: 0.82,
|
|
858
|
+
lastUpdatedAt: now,
|
|
859
|
+
};
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
private async _tinyfishMarket(now: string): Promise<MarketResearch> {
|
|
863
|
+
const searchPrompt = [
|
|
864
|
+
`Research how people with this builder profile are making money right now on the open web.`,
|
|
865
|
+
`Return STRICT JSON with keys: researchSummary, topPaths, avoidPaths, nextMoves, evidence.`,
|
|
866
|
+
`Each topPaths item must include: title, category, fitScore, speedToMoney, marketDemand, sustainability, executionDifficulty, whyItFits, examples, channels, firstSteps, risks.`,
|
|
867
|
+
`Allowed categories: fastest-path, compounding-path, hybrid-path, safe-path.`,
|
|
868
|
+
`Builder archetype tags: ${this.identity.archetypeTags.join(', ')}`,
|
|
869
|
+
`Strength tags: ${this.identity.strengthTags.join(', ')}`,
|
|
870
|
+
`Work fit tags: ${this.identity.workFitTags.join(', ')}`,
|
|
871
|
+
`Money mode tags: ${this.identity.moneyModeTags.join(', ')}`,
|
|
872
|
+
`Goal now: ${this.profile.goalNow}`,
|
|
873
|
+
`Recent work: ${this.profile.recentWork}`,
|
|
874
|
+
`Constraints: ${this.profile.constraints}`,
|
|
875
|
+
`Links: ${this.profile.links.join(', ') || 'none'}`,
|
|
876
|
+
`Find realistic, current, internet-visible monetization paths with emphasis on quickest plausible route to money and strongest long-term compounding path.`,
|
|
877
|
+
].join('\n');
|
|
878
|
+
|
|
879
|
+
const parsed = await this._runTinyFishSearch(searchPrompt);
|
|
880
|
+
const heuristic = this._heuristicMarket(now);
|
|
881
|
+
|
|
882
|
+
return {
|
|
883
|
+
status: 'tinyfish',
|
|
884
|
+
researchSummary: String(parsed.researchSummary || heuristic.researchSummary),
|
|
885
|
+
topPaths: Array.isArray(parsed.topPaths) && parsed.topPaths.length > 0
|
|
886
|
+
? parsed.topPaths.slice(0, 5).map((item: any) => ({
|
|
887
|
+
title: String(item.title || 'Untitled path'),
|
|
888
|
+
category: this._allowedPathCategory(String(item.category || 'hybrid-path')),
|
|
889
|
+
fitScore: this._toUnit(item.fitScore, 0.7),
|
|
890
|
+
speedToMoney: this._toUnit(item.speedToMoney, 0.6),
|
|
891
|
+
marketDemand: this._toUnit(item.marketDemand, 0.6),
|
|
892
|
+
sustainability: this._toUnit(item.sustainability, 0.65),
|
|
893
|
+
executionDifficulty: this._toUnit(item.executionDifficulty, 0.5),
|
|
894
|
+
whyItFits: String(item.whyItFits || ''),
|
|
895
|
+
examples: this._stringArray(item.examples),
|
|
896
|
+
channels: this._stringArray(item.channels),
|
|
897
|
+
firstSteps: this._stringArray(item.firstSteps),
|
|
898
|
+
risks: this._stringArray(item.risks),
|
|
899
|
+
}))
|
|
900
|
+
: heuristic.topPaths,
|
|
901
|
+
avoidPaths: this._stringArray(parsed.avoidPaths).slice(0, 5),
|
|
902
|
+
nextMoves: this._stringArray(parsed.nextMoves).slice(0, 6),
|
|
903
|
+
evidence: this._normalizeEvidence(parsed.evidence),
|
|
904
|
+
lastUpdatedAt: now,
|
|
905
|
+
};
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
private async _runTinyFishSearch(goal: string): Promise<any> {
|
|
909
|
+
const query = encodeURIComponent(
|
|
910
|
+
`${this.profile.headline} ${this.profile.goalNow} ${this.identity.archetypeTags.join(' ')} ways to make money`
|
|
911
|
+
);
|
|
912
|
+
const response = await fetch('https://agent.tinyfish.ai/v1/automation/run-async', {
|
|
913
|
+
method: 'POST',
|
|
914
|
+
headers: {
|
|
915
|
+
'Content-Type': 'application/json',
|
|
916
|
+
'X-API-Key': this.tinyfishApiKey,
|
|
917
|
+
},
|
|
918
|
+
body: JSON.stringify({
|
|
919
|
+
url: `https://duckduckgo.com/?q=${query}`,
|
|
920
|
+
goal: `${goal}\nRespond in strict JSON only.`,
|
|
921
|
+
browser_profile: 'lite',
|
|
922
|
+
api_integration: 'builder-compass',
|
|
923
|
+
}),
|
|
924
|
+
});
|
|
925
|
+
|
|
926
|
+
if (!response.ok) {
|
|
927
|
+
throw new Error(`TinyFish run failed with ${response.status}`);
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
const started = (await response.json()) as TinyFishRunResponse;
|
|
931
|
+
if (!started.run_id) {
|
|
932
|
+
throw new Error(started.error?.message || 'TinyFish did not return a run ID');
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
const result = await this._pollTinyFishRun(started.run_id);
|
|
936
|
+
return this._extractJson(result);
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
private async _pollTinyFishRun(runId: string): Promise<any> {
|
|
940
|
+
for (let attempt = 0; attempt < 18; attempt++) {
|
|
941
|
+
await new Promise((resolve) => setTimeout(resolve, 2500));
|
|
942
|
+
const response = await fetch(`https://agent.tinyfish.ai/v1/runs/${runId}`, {
|
|
943
|
+
headers: {
|
|
944
|
+
'X-API-Key': this.tinyfishApiKey,
|
|
945
|
+
},
|
|
946
|
+
});
|
|
947
|
+
|
|
948
|
+
if (!response.ok) {
|
|
949
|
+
continue;
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
const payload = (await response.json()) as Record<string, any>;
|
|
953
|
+
if (payload.status === 'COMPLETED') {
|
|
954
|
+
return payload.result || payload.resultJson || payload;
|
|
955
|
+
}
|
|
956
|
+
if (payload.status === 'FAILED' || payload.status === 'CANCELLED') {
|
|
957
|
+
throw new Error(payload.error?.message || `TinyFish run ${payload.status}`);
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
throw new Error('TinyFish run timed out');
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
private _extractJson(value: any): any {
|
|
965
|
+
if (typeof value === 'object' && value !== null) {
|
|
966
|
+
return value;
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
const text = String(value || '').trim();
|
|
970
|
+
try {
|
|
971
|
+
return JSON.parse(text);
|
|
972
|
+
} catch {
|
|
973
|
+
const match = text.match(/\{[\s\S]*\}/);
|
|
974
|
+
if (!match) {
|
|
975
|
+
throw new Error('TinyFish result did not contain JSON');
|
|
976
|
+
}
|
|
977
|
+
return JSON.parse(match[0]);
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
private _buildStrengthMatrix(
|
|
982
|
+
strengths: StrengthTag[],
|
|
983
|
+
risks: RiskTag[],
|
|
984
|
+
workFits: WorkFitTag[]
|
|
985
|
+
): StrengthMatrixRow[] {
|
|
986
|
+
const has = (value: StrengthTag) => strengths.includes(value);
|
|
987
|
+
const riskBias = risks.length * 0.03;
|
|
988
|
+
const founderBias = workFits.includes('founder-path') ? 0.08 : 0;
|
|
989
|
+
|
|
990
|
+
const rows: StrengthMatrixRow[] = [
|
|
991
|
+
this._row(
|
|
992
|
+
'Systems thinking',
|
|
993
|
+
has('systems-thinking') ? 0.87 : 0.68,
|
|
994
|
+
0.78,
|
|
995
|
+
has('systems-thinking') ? 0.82 : 0.61,
|
|
996
|
+
0.92,
|
|
997
|
+
0.28 + riskBias,
|
|
998
|
+
'You appear to naturally reason in systems, flows, and interdependencies.',
|
|
999
|
+
has('systems-thinking') ? 'natural aptitude' : 'learned competence'
|
|
1000
|
+
),
|
|
1001
|
+
this._row(
|
|
1002
|
+
'Product intuition',
|
|
1003
|
+
has('product-intuition') ? 0.84 : 0.58,
|
|
1004
|
+
0.74,
|
|
1005
|
+
has('product-intuition') ? 0.86 : 0.57,
|
|
1006
|
+
0.93,
|
|
1007
|
+
0.24 + founderBias,
|
|
1008
|
+
'You seem to notice wedge, user friction, and leverage rather than only implementation detail.',
|
|
1009
|
+
has('product-intuition') ? 'natural aptitude' : 'learned competence'
|
|
1010
|
+
),
|
|
1011
|
+
this._row(
|
|
1012
|
+
'Rapid prototyping',
|
|
1013
|
+
has('rapid-prototyping') ? 0.91 : 0.63,
|
|
1014
|
+
0.8,
|
|
1015
|
+
has('rapid-prototyping') ? 0.9 : 0.66,
|
|
1016
|
+
0.88,
|
|
1017
|
+
0.42 + riskBias,
|
|
1018
|
+
'You likely generate momentum by making things tangible quickly.',
|
|
1019
|
+
has('rapid-prototyping') ? 'natural aptitude' : 'learned competence'
|
|
1020
|
+
),
|
|
1021
|
+
this._row(
|
|
1022
|
+
'Execution consistency',
|
|
1023
|
+
has('execution') ? 0.71 : 0.49,
|
|
1024
|
+
0.58,
|
|
1025
|
+
has('execution') ? 0.68 : 0.45,
|
|
1026
|
+
0.9,
|
|
1027
|
+
risks.includes('weak-finish-loops') ? 0.72 : 0.44,
|
|
1028
|
+
'Sustained finishing loops are often the difference between leverage and drift.',
|
|
1029
|
+
has('execution') ? 'learned competence' : 'aspirational identity'
|
|
1030
|
+
),
|
|
1031
|
+
this._row(
|
|
1032
|
+
'Communication',
|
|
1033
|
+
has('communication') ? 0.82 : 0.59,
|
|
1034
|
+
0.72,
|
|
1035
|
+
has('communication') ? 0.78 : 0.54,
|
|
1036
|
+
0.82,
|
|
1037
|
+
0.22 + founderBias,
|
|
1038
|
+
'Clear articulation increases distribution, trust, and founder/consulting leverage.',
|
|
1039
|
+
has('communication') ? 'learned competence' : 'aspirational identity'
|
|
1040
|
+
),
|
|
1041
|
+
this._row(
|
|
1042
|
+
'Judgment',
|
|
1043
|
+
has('judgment') ? 0.76 : 0.55,
|
|
1044
|
+
0.63,
|
|
1045
|
+
has('judgment') ? 0.73 : 0.52,
|
|
1046
|
+
0.92,
|
|
1047
|
+
0.39 + riskBias,
|
|
1048
|
+
'Judgment is what keeps speed and AI leverage from turning into incoherence.',
|
|
1049
|
+
has('judgment') ? 'natural aptitude' : 'learned competence'
|
|
1050
|
+
),
|
|
1051
|
+
];
|
|
1052
|
+
|
|
1053
|
+
return rows;
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
private _row(
|
|
1057
|
+
category: string,
|
|
1058
|
+
score: number,
|
|
1059
|
+
confidence: number,
|
|
1060
|
+
energyFit: number,
|
|
1061
|
+
strategicRelevance: number,
|
|
1062
|
+
riskLoad: number,
|
|
1063
|
+
rationale: string,
|
|
1064
|
+
basis: StrengthMatrixRow['basis']
|
|
1065
|
+
): StrengthMatrixRow {
|
|
1066
|
+
return {
|
|
1067
|
+
category,
|
|
1068
|
+
score: Number(score.toFixed(2)),
|
|
1069
|
+
confidence: Number(confidence.toFixed(2)),
|
|
1070
|
+
energyFit: Number(energyFit.toFixed(2)),
|
|
1071
|
+
strategicRelevance: Number(strategicRelevance.toFixed(2)),
|
|
1072
|
+
riskLoad: Number(Math.min(1, riskLoad).toFixed(2)),
|
|
1073
|
+
rationale,
|
|
1074
|
+
basis,
|
|
1075
|
+
};
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
private _normalizeEvidence(items: any): LinkEvidence[] {
|
|
1079
|
+
if (!Array.isArray(items)) return [];
|
|
1080
|
+
return items
|
|
1081
|
+
.map((item) => ({
|
|
1082
|
+
label: String(item.label || 'Source'),
|
|
1083
|
+
url: String(item.url || ''),
|
|
1084
|
+
reason: String(item.reason || item.note || ''),
|
|
1085
|
+
}))
|
|
1086
|
+
.filter((item) => item.url)
|
|
1087
|
+
.slice(0, 6);
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
private _filterAllowed<T extends string>(values: any, allowed: T[]): T[] {
|
|
1091
|
+
if (!Array.isArray(values)) return [];
|
|
1092
|
+
return this._dedupe(values.map(String).filter((value): value is T => allowed.includes(value as T)));
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
private _stringArray(value: any): string[] {
|
|
1096
|
+
if (!Array.isArray(value)) return [];
|
|
1097
|
+
return this._dedupe(value.map((item) => String(item).trim()).filter(Boolean));
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
private _toUnit(value: any, fallback: number): number {
|
|
1101
|
+
const numeric = Number(value);
|
|
1102
|
+
if (Number.isFinite(numeric)) {
|
|
1103
|
+
if (numeric > 1) return Number(Math.min(1, numeric / 100).toFixed(2));
|
|
1104
|
+
return Number(Math.max(0, Math.min(1, numeric)).toFixed(2));
|
|
1105
|
+
}
|
|
1106
|
+
return fallback;
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
private _allowedPathCategory(value: string): MoneyPath['category'] {
|
|
1110
|
+
if (value === 'fastest-path' || value === 'compounding-path' || value === 'hybrid-path' || value === 'safe-path') {
|
|
1111
|
+
return value;
|
|
1112
|
+
}
|
|
1113
|
+
return 'hybrid-path';
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
private _labelize(value: string): string {
|
|
1117
|
+
return value
|
|
1118
|
+
.replace(/-/g, ' ')
|
|
1119
|
+
.replace(/\b\w/g, (char) => char.toUpperCase());
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
private _dedupe<T>(items: T[]): T[] {
|
|
1123
|
+
return Array.from(new Set(items));
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
private _allTags<T extends string>(items: T[]): string {
|
|
1127
|
+
return items.join(', ');
|
|
1128
|
+
}
|
|
1129
|
+
}
|