fullstackgtm 0.44.0 → 0.46.0
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/CHANGELOG.md +293 -1
- package/INSTALL_FOR_AGENTS.md +13 -11
- package/README.md +45 -24
- package/dist/audit.d.ts +3 -1
- package/dist/audit.js +29 -2
- package/dist/backfill.d.ts +86 -0
- package/dist/backfill.js +251 -0
- package/dist/bin.js +4 -1
- package/dist/cli/audit.d.ts +15 -0
- package/dist/cli/audit.js +392 -0
- package/dist/cli/auth.d.ts +82 -0
- package/dist/cli/auth.js +607 -0
- package/dist/cli/backfill.d.ts +1 -0
- package/dist/cli/backfill.js +125 -0
- package/dist/cli/backfillRuns.d.ts +1 -0
- package/dist/cli/backfillRuns.js +187 -0
- package/dist/cli/call.d.ts +1 -0
- package/dist/cli/call.js +387 -0
- package/dist/cli/capabilities.d.ts +30 -0
- package/dist/cli/capabilities.js +197 -0
- package/dist/cli/draft.d.ts +7 -0
- package/dist/cli/draft.js +87 -0
- package/dist/cli/enrich.d.ts +8 -0
- package/dist/cli/enrich.js +806 -0
- package/dist/cli/fix.d.ts +33 -0
- package/dist/cli/fix.js +346 -0
- package/dist/cli/help.d.ts +25 -0
- package/dist/cli/help.js +646 -0
- package/dist/cli/icp.d.ts +7 -0
- package/dist/cli/icp.js +229 -0
- package/dist/cli/init.d.ts +7 -0
- package/dist/cli/init.js +58 -0
- package/dist/cli/market.d.ts +1 -0
- package/dist/cli/market.js +391 -0
- package/dist/cli/plans.d.ts +5 -0
- package/dist/cli/plans.js +456 -0
- package/dist/cli/schedule.d.ts +8 -0
- package/dist/cli/schedule.js +479 -0
- package/dist/cli/shared.d.ts +71 -0
- package/dist/cli/shared.js +342 -0
- package/dist/cli/signals.d.ts +7 -0
- package/dist/cli/signals.js +412 -0
- package/dist/cli/suggest.d.ts +49 -0
- package/dist/cli/suggest.js +135 -0
- package/dist/cli/tam.d.ts +9 -0
- package/dist/cli/tam.js +387 -0
- package/dist/cli/ui.d.ts +142 -0
- package/dist/cli/ui.js +427 -0
- package/dist/cli.d.ts +1 -57
- package/dist/cli.js +123 -5157
- package/dist/connector.d.ts +23 -0
- package/dist/connector.js +47 -0
- package/dist/connectors/hubspot.d.ts +10 -1
- package/dist/connectors/hubspot.js +244 -10
- package/dist/connectors/hubspotAuth.js +5 -1
- package/dist/connectors/linkedin.js +14 -14
- package/dist/connectors/salesforce.d.ts +10 -1
- package/dist/connectors/salesforce.js +39 -6
- package/dist/connectors/signalSources.js +7 -59
- package/dist/connectors/stripe.d.ts +37 -0
- package/dist/connectors/stripe.js +103 -31
- package/dist/enrich.d.ts +7 -0
- package/dist/enrich.js +7 -0
- package/dist/health.d.ts +11 -69
- package/dist/health.js +4 -134
- package/dist/healthScore.d.ts +71 -0
- package/dist/healthScore.js +143 -0
- package/dist/icp.d.ts +15 -11
- package/dist/icp.js +19 -36
- package/dist/index.d.ts +3 -1
- package/dist/index.js +3 -1
- package/dist/judge.d.ts +2 -0
- package/dist/judge.js +6 -0
- package/dist/llm.d.ts +29 -0
- package/dist/llm.js +206 -0
- package/dist/market.d.ts +39 -1
- package/dist/market.js +116 -44
- package/dist/marketClassify.d.ts +11 -1
- package/dist/marketClassify.js +17 -2
- package/dist/marketTaxonomy.d.ts +6 -1
- package/dist/marketTaxonomy.js +4 -2
- package/dist/mcp-bin.js +31 -2
- package/dist/mcp.js +372 -166
- package/dist/progress.d.ts +96 -0
- package/dist/progress.js +142 -0
- package/dist/runReport.d.ts +24 -0
- package/dist/runReport.js +139 -4
- package/dist/schedule.d.ts +80 -2
- package/dist/schedule.js +254 -1
- package/dist/spoolFiles.d.ts +44 -0
- package/dist/spoolFiles.js +114 -0
- package/dist/types.d.ts +29 -1
- package/docs/api.md +75 -8
- package/docs/architecture.md +2 -0
- package/docs/linkedin-connector-spec.md +1 -1
- package/docs/signal-spool-format.md +13 -0
- package/llms.txt +18 -9
- package/package.json +10 -3
- package/skills/fullstackgtm/SKILL.md +2 -1
- package/src/audit.ts +27 -1
- package/src/backfill.ts +340 -0
- package/src/bin.ts +5 -1
- package/src/cli/audit.ts +447 -0
- package/src/cli/auth.ts +669 -0
- package/src/cli/backfill.ts +156 -0
- package/src/cli/backfillRuns.ts +198 -0
- package/src/cli/call.ts +414 -0
- package/src/cli/capabilities.ts +215 -0
- package/src/cli/draft.ts +101 -0
- package/src/cli/enrich.ts +908 -0
- package/src/cli/fix.ts +373 -0
- package/src/cli/help.ts +702 -0
- package/src/cli/icp.ts +265 -0
- package/src/cli/init.ts +65 -0
- package/src/cli/market.ts +423 -0
- package/src/cli/plans.ts +524 -0
- package/src/cli/schedule.ts +526 -0
- package/src/cli/shared.ts +392 -0
- package/src/cli/signals.ts +434 -0
- package/src/cli/suggest.ts +151 -0
- package/src/cli/tam.ts +435 -0
- package/src/cli/ui.ts +497 -0
- package/src/cli.ts +122 -5855
- package/src/connector.ts +66 -0
- package/src/connectors/hubspot.ts +273 -9
- package/src/connectors/hubspotAuth.ts +5 -1
- package/src/connectors/linkedin.ts +14 -14
- package/src/connectors/salesforce.ts +51 -3
- package/src/connectors/signalSources.ts +7 -56
- package/src/connectors/stripe.ts +154 -34
- package/src/enrich.ts +13 -0
- package/src/health.ts +14 -213
- package/src/healthScore.ts +223 -0
- package/src/icp.ts +19 -35
- package/src/index.ts +28 -1
- package/src/judge.ts +7 -0
- package/src/llm.ts +239 -0
- package/src/market.ts +157 -44
- package/src/marketClassify.ts +26 -2
- package/src/marketTaxonomy.ts +10 -2
- package/src/mcp-bin.ts +34 -2
- package/src/mcp.ts +270 -63
- package/src/progress.ts +197 -0
- package/src/runReport.ts +159 -4
- package/src/schedule.ts +310 -3
- package/src/spoolFiles.ts +116 -0
- package/src/types.ts +32 -2
- package/docs/dx-punch-list.md +0 -87
- package/docs/roadmap-to-1.0.md +0 -211
package/dist/market.js
CHANGED
|
@@ -4,6 +4,7 @@ import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from
|
|
|
4
4
|
import { isIP } from "node:net";
|
|
5
5
|
import { join } from "node:path";
|
|
6
6
|
import { credentialsDir } from "./credentials.js";
|
|
7
|
+
import { MARKET_CAPTURE_STAGES, nullProgressEmitter } from "./progress.js";
|
|
7
8
|
const INTENSITY_RANK = {
|
|
8
9
|
loud: 3,
|
|
9
10
|
quiet: 2,
|
|
@@ -283,58 +284,57 @@ const defaultFetchPage = async (url) => {
|
|
|
283
284
|
throw new Error(`market capture: too many redirects (>${MAX_REDIRECTS}) for ${url}`);
|
|
284
285
|
};
|
|
285
286
|
export async function captureMarket(config, options = {}) {
|
|
286
|
-
const
|
|
287
|
+
const store = options.store ?? createFileMarketStore(config.category, { capturesDir: options.dir });
|
|
288
|
+
const progress = options.progress ?? nullProgressEmitter();
|
|
287
289
|
const runLabel = options.runLabel ?? "run-1";
|
|
288
290
|
const fetchPage = options.fetchPage ?? defaultFetchPage;
|
|
289
291
|
const fetchedAt = (options.now ?? (() => new Date()))().toISOString();
|
|
290
|
-
|
|
291
|
-
const
|
|
292
|
-
const manifest = existsSync(manifestPath)
|
|
293
|
-
? JSON.parse(readFileSync(manifestPath, "utf8"))
|
|
294
|
-
: [];
|
|
295
|
-
const entries = [];
|
|
292
|
+
progress.stage(MARKET_CAPTURE_STAGES[0], 0, MARKET_CAPTURE_STAGES.length);
|
|
293
|
+
const targets = [];
|
|
296
294
|
for (const vendor of config.vendors) {
|
|
297
|
-
|
|
298
|
-
{ kind: "home", url: vendor.urls.home },
|
|
299
|
-
];
|
|
295
|
+
targets.push({ vendorId: vendor.id, kind: "home", url: vendor.urls.home });
|
|
300
296
|
if (vendor.urls.pricing)
|
|
301
|
-
targets.push({ kind: "pricing", url: vendor.urls.pricing });
|
|
297
|
+
targets.push({ vendorId: vendor.id, kind: "pricing", url: vendor.urls.pricing });
|
|
302
298
|
for (const url of vendor.urls.product)
|
|
303
|
-
targets.push({ kind: "product", url });
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
// Content-addressed: an unchanged page dedupes to the same file.
|
|
320
|
-
writeFileSync(join(dir, `${captureHash}.txt`), text);
|
|
321
|
-
}
|
|
322
|
-
const entry = {
|
|
323
|
-
runLabel,
|
|
324
|
-
vendorId: vendor.id,
|
|
325
|
-
kind: target.kind,
|
|
326
|
-
url: target.url,
|
|
327
|
-
fetchedAt,
|
|
328
|
-
httpStatus: status,
|
|
329
|
-
captureHash,
|
|
330
|
-
textChars: text.length,
|
|
331
|
-
};
|
|
332
|
-
manifest.push(entry);
|
|
333
|
-
entries.push(entry);
|
|
299
|
+
targets.push({ vendorId: vendor.id, kind: "product", url });
|
|
300
|
+
}
|
|
301
|
+
progress.note(`${config.vendors.length} vendor(s), ${targets.length} page(s)`);
|
|
302
|
+
progress.stage(MARKET_CAPTURE_STAGES[1], 1, MARKET_CAPTURE_STAGES.length);
|
|
303
|
+
const entries = [];
|
|
304
|
+
for (const target of targets) {
|
|
305
|
+
let status = null;
|
|
306
|
+
let text = "";
|
|
307
|
+
try {
|
|
308
|
+
const page = await fetchPage(target.url);
|
|
309
|
+
status = page.status;
|
|
310
|
+
if (page.status === 200)
|
|
311
|
+
text = extractReadableText(page.body);
|
|
312
|
+
}
|
|
313
|
+
catch {
|
|
314
|
+
status = null;
|
|
334
315
|
}
|
|
316
|
+
let captureHash = null;
|
|
317
|
+
if (text) {
|
|
318
|
+
captureHash = createHash("sha256").update(text).digest("hex");
|
|
319
|
+
// Content-addressed: an unchanged page dedupes to the same key.
|
|
320
|
+
await store.saveCaptureText(captureHash, text);
|
|
321
|
+
}
|
|
322
|
+
entries.push({
|
|
323
|
+
runLabel,
|
|
324
|
+
vendorId: target.vendorId,
|
|
325
|
+
kind: target.kind,
|
|
326
|
+
url: target.url,
|
|
327
|
+
fetchedAt,
|
|
328
|
+
httpStatus: status,
|
|
329
|
+
captureHash,
|
|
330
|
+
textChars: text.length,
|
|
331
|
+
});
|
|
332
|
+
progress.items(entries.length, targets.length);
|
|
335
333
|
}
|
|
336
|
-
|
|
337
|
-
|
|
334
|
+
progress.stage(MARKET_CAPTURE_STAGES[3], 3, MARKET_CAPTURE_STAGES.length);
|
|
335
|
+
await store.appendCaptureEntries(entries);
|
|
336
|
+
progress.flush();
|
|
337
|
+
return { entries, manifestPath: store.captureLocation() };
|
|
338
338
|
}
|
|
339
339
|
export function createFileObservationStore(category, directory) {
|
|
340
340
|
const dir = directory ?? join(marketHome(category), "observations");
|
|
@@ -459,6 +459,78 @@ export function loadCaptureTexts(category, directory) {
|
|
|
459
459
|
}
|
|
460
460
|
return { entries, textByHash };
|
|
461
461
|
}
|
|
462
|
+
/** The CLI's store: captures + observations under the profile market home. */
|
|
463
|
+
export function createFileMarketStore(category, options = {}) {
|
|
464
|
+
const dir = options.capturesDir ?? join(marketHome(category), "captures");
|
|
465
|
+
const manifestPath = join(dir, "manifest.json");
|
|
466
|
+
return {
|
|
467
|
+
captureLocation: () => manifestPath,
|
|
468
|
+
async saveCaptureText(captureHash, text) {
|
|
469
|
+
mkdirSync(dir, { recursive: true });
|
|
470
|
+
writeFileSync(join(dir, `${captureHash}.txt`), text);
|
|
471
|
+
},
|
|
472
|
+
async appendCaptureEntries(entries) {
|
|
473
|
+
mkdirSync(dir, { recursive: true });
|
|
474
|
+
const manifest = existsSync(manifestPath)
|
|
475
|
+
? JSON.parse(readFileSync(manifestPath, "utf8"))
|
|
476
|
+
: [];
|
|
477
|
+
manifest.push(...entries);
|
|
478
|
+
writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`);
|
|
479
|
+
},
|
|
480
|
+
async loadCaptureTexts() {
|
|
481
|
+
return loadCaptureTexts(category, dir);
|
|
482
|
+
},
|
|
483
|
+
observations: createFileObservationStore(category, options.observationsDir),
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
/**
|
|
487
|
+
* In-memory store: seam tests, and throwaway grounding captures (e.g. the
|
|
488
|
+
* taxonomy proposer's bootstrap pass) that should never persist anywhere.
|
|
489
|
+
*/
|
|
490
|
+
export function createMemoryMarketStore(category) {
|
|
491
|
+
const entries = [];
|
|
492
|
+
const textByHash = new Map();
|
|
493
|
+
const sets = new Map();
|
|
494
|
+
const sorted = () => [...sets.values()].sort((a, b) => a.runAt.localeCompare(b.runAt));
|
|
495
|
+
return {
|
|
496
|
+
captureLocation: () => `memory://${category}/captures`,
|
|
497
|
+
async saveCaptureText(captureHash, text) {
|
|
498
|
+
textByHash.set(captureHash, text);
|
|
499
|
+
},
|
|
500
|
+
async appendCaptureEntries(newEntries) {
|
|
501
|
+
entries.push(...newEntries);
|
|
502
|
+
},
|
|
503
|
+
async loadCaptureTexts() {
|
|
504
|
+
return { entries: [...entries], textByHash: new Map(textByHash) };
|
|
505
|
+
},
|
|
506
|
+
observations: {
|
|
507
|
+
async append(set) {
|
|
508
|
+
if (set.category !== category) {
|
|
509
|
+
throw new Error(`Observation set category "${set.category}" does not match store "${category}"`);
|
|
510
|
+
}
|
|
511
|
+
if (sets.has(set.runLabel)) {
|
|
512
|
+
throw new Error(`Run "${set.runLabel}" already exists — observations are append-only; use a new run label`);
|
|
513
|
+
}
|
|
514
|
+
sets.set(set.runLabel, set);
|
|
515
|
+
return set;
|
|
516
|
+
},
|
|
517
|
+
async get(runLabel) {
|
|
518
|
+
return sets.get(runLabel) ?? null;
|
|
519
|
+
},
|
|
520
|
+
async list() {
|
|
521
|
+
return sorted().map((set) => ({
|
|
522
|
+
runLabel: set.runLabel,
|
|
523
|
+
runAt: set.runAt,
|
|
524
|
+
observations: set.observations.length,
|
|
525
|
+
}));
|
|
526
|
+
},
|
|
527
|
+
async latest() {
|
|
528
|
+
const all = sorted();
|
|
529
|
+
return all.length ? all[all.length - 1] : null;
|
|
530
|
+
},
|
|
531
|
+
},
|
|
532
|
+
};
|
|
533
|
+
}
|
|
462
534
|
/**
|
|
463
535
|
* Whitespace-only normalization for span matching, plus one extraction
|
|
464
536
|
* artifact: the HTML-to-text step can emit a line break before punctuation
|
package/dist/marketClassify.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type LlmCallOptions } from "./llm.ts";
|
|
2
|
-
import { type CaptureEntry, type MarketClaim, type MarketConfig, type ObservationSet } from "./market.ts";
|
|
2
|
+
import { type CaptureEntry, type MarketClaim, type MarketConfig, type MarketStore, type ObservationSet } from "./market.ts";
|
|
3
|
+
import { type ProgressEmitter } from "./progress.ts";
|
|
3
4
|
export type ClassifyMarketOptions = {
|
|
4
5
|
llm: LlmCallOptions;
|
|
5
6
|
/** Observation run label to produce; must be new (the store is append-only). */
|
|
@@ -10,7 +11,16 @@ export type ClassifyMarketOptions = {
|
|
|
10
11
|
vendors?: string[];
|
|
11
12
|
/** Captures directory override (tests); defaults to the profile market home. */
|
|
12
13
|
capturesDir?: string;
|
|
14
|
+
/** Storage seam: when given, captures are read through it instead of the file layout. */
|
|
15
|
+
store?: MarketStore;
|
|
13
16
|
now?: () => Date;
|
|
17
|
+
/** Per-vendor progress (presentation only — a throwing callback never fails the run). */
|
|
18
|
+
onVendor?: (done: number, total: number, vendorId: string) => void;
|
|
19
|
+
/**
|
|
20
|
+
* Progress emission over MARKET_CAPTURE_STAGES (the "classify" stage, items
|
|
21
|
+
* per vendor). Presentation-only: a throwing listener never fails the run.
|
|
22
|
+
*/
|
|
23
|
+
progress?: ProgressEmitter;
|
|
14
24
|
};
|
|
15
25
|
export type ClassifyMarketResult = {
|
|
16
26
|
set: ObservationSet;
|
package/dist/marketClassify.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { DEFAULT_MODELS, forcedToolCall } from "./llm.js";
|
|
2
2
|
import { loadCaptureTexts, observationId, verifyEvidenceSpans, } from "./market.js";
|
|
3
|
+
import { MARKET_CAPTURE_STAGES, nullProgressEmitter } from "./progress.js";
|
|
3
4
|
/**
|
|
4
5
|
* LLM intensity classification for the market map — the same
|
|
5
6
|
* semi-deterministic posture as call extraction, with one upgrade calls
|
|
@@ -78,7 +79,10 @@ function claimsBlock(claims) {
|
|
|
78
79
|
}
|
|
79
80
|
export async function classifyMarket(config, options) {
|
|
80
81
|
const model = options.llm.model ?? DEFAULT_MODELS[options.llm.provider];
|
|
81
|
-
const
|
|
82
|
+
const progress = options.progress ?? nullProgressEmitter();
|
|
83
|
+
const { entries, textByHash } = options.store
|
|
84
|
+
? await options.store.loadCaptureTexts()
|
|
85
|
+
: loadCaptureTexts(config.category, options.capturesDir);
|
|
82
86
|
if (entries.length === 0) {
|
|
83
87
|
throw new Error(`No captures for ${config.category} — run \`market capture\` first`);
|
|
84
88
|
}
|
|
@@ -92,7 +96,15 @@ export async function classifyMarket(config, options) {
|
|
|
92
96
|
const claimIds = config.claims.map((claim) => claim.id);
|
|
93
97
|
const observations = [];
|
|
94
98
|
const retriedVendorIds = [];
|
|
95
|
-
|
|
99
|
+
progress.stage(MARKET_CAPTURE_STAGES[2], 2, MARKET_CAPTURE_STAGES.length);
|
|
100
|
+
for (const [vendorIndex, vendorId] of vendorIds.entries()) {
|
|
101
|
+
try {
|
|
102
|
+
options.onVendor?.(vendorIndex, vendorIds.length, vendorId);
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
// progress is presentation-only
|
|
106
|
+
}
|
|
107
|
+
progress.note(vendorId);
|
|
96
108
|
const vendor = config.vendors.find((candidate) => candidate.id === vendorId);
|
|
97
109
|
if (!vendor)
|
|
98
110
|
throw new Error(`Unknown vendor "${vendorId}"`);
|
|
@@ -114,6 +126,7 @@ export async function classifyMarket(config, options) {
|
|
|
114
126
|
evidence: [],
|
|
115
127
|
});
|
|
116
128
|
}
|
|
129
|
+
progress.items(vendorIndex + 1, vendorIds.length);
|
|
117
130
|
continue;
|
|
118
131
|
}
|
|
119
132
|
const prompt = (feedback) => `${CLASSIFY_INSTRUCTIONS}\n\nSurface rule for this category:\n${config.surfaceRule ?? "(default rule above)"}\n\nClaims to classify (all of them):\n${claimsBlock(config.claims)}\n${feedback}\nVendor: ${vendor.name}\nCaptured pages:\n${dossier}`;
|
|
@@ -159,7 +172,9 @@ export async function classifyMarket(config, options) {
|
|
|
159
172
|
}
|
|
160
173
|
for (const reading of outcome.readings)
|
|
161
174
|
observations.push(toObservation(reading, vendorId));
|
|
175
|
+
progress.items(vendorIndex + 1, vendorIds.length);
|
|
162
176
|
}
|
|
177
|
+
progress.flush();
|
|
163
178
|
return {
|
|
164
179
|
set: {
|
|
165
180
|
id: `set_${config.category}_${options.runLabel}`,
|
package/dist/marketTaxonomy.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type LlmCallOptions } from "./llm.ts";
|
|
2
|
-
import { type FetchPage, type MarketConfig } from "./market.ts";
|
|
2
|
+
import { type FetchPage, type MarketConfig, type MarketStore } from "./market.ts";
|
|
3
3
|
/**
|
|
4
4
|
* Cold-start taxonomy bootstrap. `market init` writes a stub for a human
|
|
5
5
|
* analyst to fill in; the self-serve hosted map has no analyst in the loop, so
|
|
@@ -30,6 +30,11 @@ export type SuggestTaxonomyOptions = {
|
|
|
30
30
|
/** Test injectables. */
|
|
31
31
|
fetchPage?: FetchPage;
|
|
32
32
|
capturesDir?: string;
|
|
33
|
+
/**
|
|
34
|
+
* Storage seam for the bootstrap captures; defaults to the file layout.
|
|
35
|
+
* Pass createMemoryMarketStore for throwaway grounding (hosted flow).
|
|
36
|
+
*/
|
|
37
|
+
store?: MarketStore;
|
|
33
38
|
now?: () => Date;
|
|
34
39
|
};
|
|
35
40
|
export type SuggestTaxonomyResult = {
|
package/dist/marketTaxonomy.js
CHANGED
|
@@ -147,8 +147,10 @@ export async function suggestMarketConfig(options) {
|
|
|
147
147
|
const anchorId = anchorSeed ? vendors[options.vendors.indexOf(anchorSeed)]?.id : undefined;
|
|
148
148
|
// Capture the seed homepages so the proposer only sees text we actually
|
|
149
149
|
// fetched (the SSRF guard in captureMarket applies to these user-supplied URLs).
|
|
150
|
-
await captureMarket({ category, vendors, claims: [] }, { dir: options.capturesDir, runLabel: "bootstrap", fetchPage: options.fetchPage, now: options.now });
|
|
151
|
-
const capture =
|
|
150
|
+
await captureMarket({ category, vendors, claims: [] }, { dir: options.capturesDir, store: options.store, runLabel: "bootstrap", fetchPage: options.fetchPage, now: options.now });
|
|
151
|
+
const capture = options.store
|
|
152
|
+
? await options.store.loadCaptureTexts()
|
|
153
|
+
: loadCaptureTexts(category, options.capturesDir);
|
|
152
154
|
const { dossier, unreadable } = buildDossier(vendors, capture, perVendorChars);
|
|
153
155
|
if (!dossier.trim()) {
|
|
154
156
|
throw new Error(`market init --auto: none of the ${vendors.length} seed pages returned readable text — check the URLs are public homepages.`);
|
package/dist/mcp-bin.js
CHANGED
|
@@ -1,4 +1,33 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
const args = process.argv.slice(2);
|
|
3
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
4
|
+
console.log(`Usage: fullstackgtm-mcp [--help] [--version]
|
|
5
|
+
|
|
6
|
+
Starts the fullstackgtm MCP stdio server.
|
|
7
|
+
|
|
8
|
+
The MCP server requires optional peer dependencies:
|
|
9
|
+
@modelcontextprotocol/sdk
|
|
10
|
+
zod
|
|
11
|
+
|
|
12
|
+
Zero-install with peers:
|
|
13
|
+
npx -y -p fullstackgtm -p @modelcontextprotocol/sdk -p zod fullstackgtm-mcp`);
|
|
14
|
+
process.exit(0);
|
|
15
|
+
}
|
|
16
|
+
if (args.includes("--version") || args.includes("-v")) {
|
|
17
|
+
console.log(await readPackageVersion());
|
|
18
|
+
process.exit(0);
|
|
19
|
+
}
|
|
20
|
+
async function readPackageVersion() {
|
|
21
|
+
try {
|
|
22
|
+
const { readFileSync } = await import("node:fs");
|
|
23
|
+
const raw = readFileSync(new URL("../package.json", import.meta.url), "utf8");
|
|
24
|
+
const parsed = JSON.parse(raw);
|
|
25
|
+
return parsed.version ?? "unknown";
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return "unknown";
|
|
29
|
+
}
|
|
30
|
+
}
|
|
2
31
|
// The MCP server needs the optional peer dependencies. Import dynamically so
|
|
3
32
|
// a missing peer produces install guidance instead of a module-load stack
|
|
4
33
|
// trace — `npx fullstackgtm-mcp` alone never installs optional peers.
|
|
@@ -7,8 +36,8 @@ const MISSING_PEER_HELP = `The MCP server needs the optional peer dependencies @
|
|
|
7
36
|
In a project:
|
|
8
37
|
npm install fullstackgtm @modelcontextprotocol/sdk zod
|
|
9
38
|
|
|
10
|
-
Zero-install:
|
|
11
|
-
npx -
|
|
39
|
+
Zero-install (the fullstackgtm-mcp wrapper package bundles the peers):
|
|
40
|
+
npx -y fullstackgtm-mcp`;
|
|
12
41
|
function isMissingPeerError(error) {
|
|
13
42
|
if (!(error instanceof Error))
|
|
14
43
|
return false;
|