fullstackgtm 0.56.1 → 0.58.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 +43 -0
- package/README.md +163 -492
- package/dist/cli/enrich.d.ts +2 -2
- package/dist/cli/enrich.js +39 -12
- package/dist/cli/help.js +4 -4
- package/dist/cli/icp.js +99 -6
- package/dist/cli/signals.js +19 -4
- package/dist/enrich.d.ts +1 -1
- package/dist/enrich.js +1 -1
- package/dist/enrichZoomInfo.d.ts +33 -0
- package/dist/enrichZoomInfo.js +144 -0
- package/dist/hostedArtifacts.d.ts +35 -1
- package/dist/hostedArtifacts.js +35 -10
- package/dist/icp.d.ts +3 -0
- package/dist/icp.js +7 -4
- package/dist/icpSync.d.ts +55 -0
- package/dist/icpSync.js +93 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/runReport.js +11 -0
- package/docs/api.md +1 -1
- package/docs/architecture.md +5 -0
- package/llms.txt +3 -2
- package/package.json +2 -2
- package/src/cli/enrich.ts +40 -13
- package/src/cli/help.ts +4 -4
- package/src/cli/icp.ts +80 -5
- package/src/cli/signals.ts +20 -3
- package/src/enrich.ts +2 -2
- package/src/enrichZoomInfo.ts +197 -0
- package/src/hostedArtifacts.ts +51 -22
- package/src/icp.ts +10 -4
- package/src/icpSync.ts +74 -0
- package/src/index.ts +24 -0
- package/src/runReport.ts +12 -0
package/dist/hostedArtifacts.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/** Version-aware hosted artifact transport for a human-paired CLI profile. */
|
|
2
2
|
import { getCredential } from "./credentials.js";
|
|
3
3
|
const ENDPOINT = "/api/cli/artifact";
|
|
4
4
|
const DEFAULT_TIMEOUT_MS = 4000;
|
|
@@ -17,27 +17,52 @@ function broker() {
|
|
|
17
17
|
return null;
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
|
+
function requestOptions(accessToken, timeoutMs) {
|
|
21
|
+
return { headers: { Authorization: `Bearer ${accessToken}` }, signal: AbortSignal.timeout(timeoutMs) };
|
|
22
|
+
}
|
|
23
|
+
export async function readHostedArtifact(kind, key, options = {}) {
|
|
24
|
+
const paired = broker();
|
|
25
|
+
if (!paired)
|
|
26
|
+
return { status: "unpaired" };
|
|
27
|
+
try {
|
|
28
|
+
const url = new URL(`${paired.baseUrl}${ENDPOINT}`);
|
|
29
|
+
url.searchParams.set("kind", kind);
|
|
30
|
+
url.searchParams.set("key", key);
|
|
31
|
+
const response = await (options.fetchImpl ?? fetch)(url, requestOptions(paired.accessToken, options.timeoutMs ?? DEFAULT_TIMEOUT_MS));
|
|
32
|
+
if (response.status === 404)
|
|
33
|
+
return { status: "missing" };
|
|
34
|
+
if (!response.ok)
|
|
35
|
+
return { status: "unavailable", reason: `hosted artifact request failed (HTTP ${response.status})` };
|
|
36
|
+
const state = await response.json();
|
|
37
|
+
if (!state.artifactId || !Number.isSafeInteger(state.revision) || !state.document)
|
|
38
|
+
return { status: "unavailable", reason: "hosted artifact response was invalid" };
|
|
39
|
+
return { status: "found", state };
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return { status: "unavailable", reason: "hosted artifact request was unavailable" };
|
|
43
|
+
}
|
|
44
|
+
}
|
|
20
45
|
export async function writeHostedArtifact(artifact, options = {}) {
|
|
21
|
-
if (!artifact.key || artifact.key.length > 256 || !artifact.label || artifact.label.length > 200)
|
|
46
|
+
if (!artifact.key || artifact.key.length > 256 || !artifact.label || artifact.label.length > 200)
|
|
22
47
|
throw new Error("Hosted artifact key/label is invalid.");
|
|
23
|
-
}
|
|
24
48
|
const paired = broker();
|
|
25
49
|
if (!paired)
|
|
26
50
|
return { status: "unpaired" };
|
|
27
51
|
try {
|
|
28
52
|
const response = await (options.fetchImpl ?? fetch)(`${paired.baseUrl}${ENDPOINT}`, {
|
|
29
|
-
method: "POST",
|
|
30
|
-
headers: { Authorization: `Bearer ${paired.accessToken}`, "Content-Type": "application/json" },
|
|
31
|
-
body: JSON.stringify(artifact),
|
|
32
|
-
signal: AbortSignal.timeout(options.timeoutMs ?? DEFAULT_TIMEOUT_MS),
|
|
53
|
+
method: "POST", ...requestOptions(paired.accessToken, options.timeoutMs ?? DEFAULT_TIMEOUT_MS),
|
|
54
|
+
headers: { Authorization: `Bearer ${paired.accessToken}`, "Content-Type": "application/json" }, body: JSON.stringify(artifact),
|
|
33
55
|
});
|
|
56
|
+
if (response.status === 409) {
|
|
57
|
+
const body = await response.json();
|
|
58
|
+
return { status: "conflict", reason: "hosted ICP changed since the last sync", currentRevision: body.currentRevision, documentSha256: body.documentSha256 };
|
|
59
|
+
}
|
|
34
60
|
if (!response.ok)
|
|
35
61
|
return { status: "unavailable", reason: `hosted artifact request failed (HTTP ${response.status})` };
|
|
36
62
|
const body = await response.json();
|
|
37
|
-
if (typeof body.created !== "boolean" || typeof body.updatedAt !== "number")
|
|
63
|
+
if (typeof body.artifactId !== "string" || typeof body.created !== "boolean" || typeof body.updatedAt !== "number" || typeof body.revision !== "number" || typeof body.documentSha256 !== "string")
|
|
38
64
|
return { status: "unavailable", reason: "hosted artifact response was invalid" };
|
|
39
|
-
}
|
|
40
|
-
return { status: "saved", created: body.created, updatedAt: body.updatedAt };
|
|
65
|
+
return { status: "saved", artifactId: body.artifactId, created: body.created, updatedAt: body.updatedAt, revision: body.revision, documentSha256: body.documentSha256, unchanged: body.unchanged === true };
|
|
41
66
|
}
|
|
42
67
|
catch {
|
|
43
68
|
return { status: "unavailable", reason: "hosted artifact request was unavailable" };
|
package/dist/icp.d.ts
CHANGED
|
@@ -71,6 +71,9 @@ export type Icp = {
|
|
|
71
71
|
scoring?: {
|
|
72
72
|
/** minimum fit (0..1) for a prospect to become a create_record op. Default 0.5. */
|
|
73
73
|
threshold?: number;
|
|
74
|
+
/** Require a literal persona.titleKeywords phrase in title/headline. This
|
|
75
|
+
* disables the broader function fallback for high-precision sourcing. */
|
|
76
|
+
requireTitleKeyword?: boolean;
|
|
74
77
|
};
|
|
75
78
|
};
|
|
76
79
|
export declare const DEFAULT_FIT_THRESHOLD = 0.5;
|
package/dist/icp.js
CHANGED
|
@@ -381,15 +381,18 @@ export function scoreProspectAgainstIcp(prospect, icp) {
|
|
|
381
381
|
const keywords = (icp.persona.titleKeywords ?? []).map((k) => k.toLowerCase());
|
|
382
382
|
const levels = (icp.persona.jobLevels ?? []).map((l) => l.toLowerCase());
|
|
383
383
|
const depts = (icp.persona.departments ?? []).map((d) => d.toLowerCase());
|
|
384
|
+
const exactTitleKeyword = keywords.find((keyword) => title.includes(keyword));
|
|
385
|
+
if (icp.scoring?.requireTitleKeyword && keywords.length && !exactTitleKeyword) {
|
|
386
|
+
return { score: 0, reasons: ["title does not contain a required ICP keyword"] };
|
|
387
|
+
}
|
|
384
388
|
let score = 0;
|
|
385
389
|
let weightSum = 0;
|
|
386
390
|
if (keywords.length) {
|
|
387
391
|
weightSum += 0.6;
|
|
388
|
-
const
|
|
389
|
-
|
|
390
|
-
if (exact) {
|
|
392
|
+
const functional = exactTitleKeyword ? undefined : roleKeywords(icp).find((keyword) => title.includes(keyword));
|
|
393
|
+
if (exactTitleKeyword) {
|
|
391
394
|
score += 0.6;
|
|
392
|
-
reasons.push(`title matches ICP keyword "${
|
|
395
|
+
reasons.push(`title matches ICP keyword "${exactTitleKeyword}"`);
|
|
393
396
|
}
|
|
394
397
|
else if (functional) {
|
|
395
398
|
score += 0.45;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { type Icp } from "./icp.ts";
|
|
2
|
+
import { type HostedArtifactState } from "./hostedArtifacts.ts";
|
|
3
|
+
export type IcpSyncState = {
|
|
4
|
+
version: 1;
|
|
5
|
+
artifactId: string;
|
|
6
|
+
key: string;
|
|
7
|
+
domain: string;
|
|
8
|
+
revision: number;
|
|
9
|
+
localIcpSha256: string;
|
|
10
|
+
hostedDocumentSha256?: string;
|
|
11
|
+
syncedAt: string;
|
|
12
|
+
};
|
|
13
|
+
export type IcpSyncStatus = {
|
|
14
|
+
state: "unpaired" | "missing_hosted" | "in_sync" | "local_changed" | "hosted_changed" | "conflict" | "untracked" | "unavailable";
|
|
15
|
+
localIcpSha256: string;
|
|
16
|
+
hostedRevision?: number;
|
|
17
|
+
trackedRevision?: number;
|
|
18
|
+
reason?: string;
|
|
19
|
+
};
|
|
20
|
+
export declare function classifyIcpSync(localHash: string, hostedRevision: number, hostedHash: string, tracked: IcpSyncState | null): IcpSyncStatus["state"];
|
|
21
|
+
export declare function canonicalJson(value: unknown): string;
|
|
22
|
+
export declare const icpSha256: (icp: Icp) => string;
|
|
23
|
+
export declare function artifactKeyForDomain(domain: string): string;
|
|
24
|
+
export declare const sidecarPathFor: (icpPath: string) => string;
|
|
25
|
+
export declare function readLocalIcp(path: string): Icp;
|
|
26
|
+
export declare function extractHostedIcp(state: HostedArtifactState): Icp;
|
|
27
|
+
export declare function readIcpSyncState(icpPath: string): IcpSyncState | null;
|
|
28
|
+
export declare function writeIcpSyncState(icpPath: string, state: IcpSyncState): void;
|
|
29
|
+
export declare function getIcpSyncStatus(icpPath: string, domain: string): Promise<{
|
|
30
|
+
status: IcpSyncStatus;
|
|
31
|
+
hosted?: HostedArtifactState;
|
|
32
|
+
local: Icp;
|
|
33
|
+
}>;
|
|
34
|
+
export declare function markIcpSynced(icpPath: string, domain: string, hosted: HostedArtifactState | {
|
|
35
|
+
artifactId: string;
|
|
36
|
+
revision: number;
|
|
37
|
+
documentSha256?: string;
|
|
38
|
+
}, icp: Icp): void;
|
|
39
|
+
export declare function pushIcp(icpPath: string, domain: string, changeSummary?: string): Promise<{
|
|
40
|
+
status: "conflict";
|
|
41
|
+
checked: {
|
|
42
|
+
status: IcpSyncStatus;
|
|
43
|
+
hosted?: HostedArtifactState;
|
|
44
|
+
local: Icp;
|
|
45
|
+
};
|
|
46
|
+
result?: undefined;
|
|
47
|
+
} | {
|
|
48
|
+
status: "conflict" | "unpaired" | "unavailable" | "saved";
|
|
49
|
+
result: import("./hostedArtifacts.ts").HostedArtifactResult;
|
|
50
|
+
checked: {
|
|
51
|
+
status: IcpSyncStatus;
|
|
52
|
+
hosted?: HostedArtifactState;
|
|
53
|
+
local: Icp;
|
|
54
|
+
};
|
|
55
|
+
}>;
|
package/dist/icpSync.js
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { existsSync, mkdirSync } from "node:fs";
|
|
3
|
+
import { dirname, resolve } from "node:path";
|
|
4
|
+
import { parseIcp } from "./icp.js";
|
|
5
|
+
import { readSecureRegularFile, writeSecureFileAtomic } from "./secureFile.js";
|
|
6
|
+
import { readHostedArtifact, writeHostedArtifact } from "./hostedArtifacts.js";
|
|
7
|
+
export function classifyIcpSync(localHash, hostedRevision, hostedHash, tracked) {
|
|
8
|
+
if (!tracked)
|
|
9
|
+
return localHash === hostedHash ? "in_sync" : "untracked";
|
|
10
|
+
const localChanged = localHash !== tracked.localIcpSha256;
|
|
11
|
+
const hostedChanged = hostedRevision !== tracked.revision;
|
|
12
|
+
return localChanged && hostedChanged ? "conflict" : localChanged ? "local_changed" : hostedChanged ? "hosted_changed" : "in_sync";
|
|
13
|
+
}
|
|
14
|
+
export function canonicalJson(value) {
|
|
15
|
+
if (value === null || typeof value !== "object")
|
|
16
|
+
return JSON.stringify(value);
|
|
17
|
+
if (Array.isArray(value))
|
|
18
|
+
return `[${value.map(canonicalJson).join(",")}]`;
|
|
19
|
+
const object = value;
|
|
20
|
+
return `{${Object.keys(object).sort().map((key) => `${JSON.stringify(key)}:${canonicalJson(object[key])}`).join(",")}}`;
|
|
21
|
+
}
|
|
22
|
+
export const icpSha256 = (icp) => createHash("sha256").update(canonicalJson(icp)).digest("hex");
|
|
23
|
+
export function artifactKeyForDomain(domain) {
|
|
24
|
+
const candidate = /^https?:\/\//i.test(domain.trim()) ? domain.trim() : `https://${domain.trim()}`;
|
|
25
|
+
let parsed;
|
|
26
|
+
try {
|
|
27
|
+
parsed = new URL(candidate);
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
throw new Error(`Invalid company domain: ${domain}`);
|
|
31
|
+
}
|
|
32
|
+
const hostname = parsed.hostname.toLowerCase().replace(/^www\./, "").replace(/\.$/, "");
|
|
33
|
+
if (!hostname.includes("."))
|
|
34
|
+
throw new Error(`Invalid public company domain: ${domain}`);
|
|
35
|
+
return `icp:${hostname}`;
|
|
36
|
+
}
|
|
37
|
+
export const sidecarPathFor = (icpPath) => resolve(dirname(resolve(icpPath)), ".fullstackgtm", `${resolve(icpPath).split(/[\\/]/).pop()}.sync.json`);
|
|
38
|
+
export function readLocalIcp(path) { return parseIcp(readSecureRegularFile(resolve(path))); }
|
|
39
|
+
export function extractHostedIcp(state) {
|
|
40
|
+
const root = state.document && typeof state.document === "object" && !Array.isArray(state.document) ? state.document : {};
|
|
41
|
+
return parseIcp(JSON.stringify(root.icp ?? state.document));
|
|
42
|
+
}
|
|
43
|
+
export function readIcpSyncState(icpPath) {
|
|
44
|
+
const path = sidecarPathFor(icpPath);
|
|
45
|
+
if (!existsSync(path))
|
|
46
|
+
return null;
|
|
47
|
+
try {
|
|
48
|
+
const value = JSON.parse(readSecureRegularFile(path));
|
|
49
|
+
return value?.version === 1 ? value : null;
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
export function writeIcpSyncState(icpPath, state) {
|
|
56
|
+
const path = sidecarPathFor(icpPath);
|
|
57
|
+
mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
|
|
58
|
+
writeSecureFileAtomic(path, `${JSON.stringify(state, null, 2)}\n`);
|
|
59
|
+
}
|
|
60
|
+
export async function getIcpSyncStatus(icpPath, domain) {
|
|
61
|
+
const local = readLocalIcp(icpPath);
|
|
62
|
+
const localHash = icpSha256(local);
|
|
63
|
+
const tracked = readIcpSyncState(icpPath);
|
|
64
|
+
const read = await readHostedArtifact("icp", artifactKeyForDomain(domain));
|
|
65
|
+
if (read.status === "unpaired")
|
|
66
|
+
return { local, status: { state: "unpaired", localIcpSha256: localHash } };
|
|
67
|
+
if (read.status === "missing")
|
|
68
|
+
return { local, status: { state: "missing_hosted", localIcpSha256: localHash } };
|
|
69
|
+
if (read.status === "unavailable")
|
|
70
|
+
return { local, status: { state: "unavailable", localIcpSha256: localHash, reason: read.reason } };
|
|
71
|
+
const hostedHash = icpSha256(extractHostedIcp(read.state));
|
|
72
|
+
const state = classifyIcpSync(localHash, read.state.revision, hostedHash, tracked);
|
|
73
|
+
return { local, hosted: read.state, status: { state, localIcpSha256: localHash, hostedRevision: read.state.revision, trackedRevision: tracked?.revision } };
|
|
74
|
+
}
|
|
75
|
+
export function markIcpSynced(icpPath, domain, hosted, icp) {
|
|
76
|
+
const key = artifactKeyForDomain(domain);
|
|
77
|
+
const normalizedDomain = key.slice("icp:".length);
|
|
78
|
+
writeIcpSyncState(icpPath, { version: 1, artifactId: hosted.artifactId, key, domain: normalizedDomain, revision: hosted.revision, localIcpSha256: icpSha256(icp), hostedDocumentSha256: hosted.documentSha256, syncedAt: new Date().toISOString() });
|
|
79
|
+
}
|
|
80
|
+
export async function pushIcp(icpPath, domain, changeSummary) {
|
|
81
|
+
const checked = await getIcpSyncStatus(icpPath, domain);
|
|
82
|
+
if (checked.status.state === "conflict" || checked.status.state === "hosted_changed" || checked.status.state === "untracked")
|
|
83
|
+
return { status: "conflict", checked };
|
|
84
|
+
const current = checked.hosted;
|
|
85
|
+
const root = current?.document && typeof current.document === "object" && !Array.isArray(current.document) ? current.document : {};
|
|
86
|
+
const key = artifactKeyForDomain(domain);
|
|
87
|
+
const normalizedDomain = key.slice("icp:".length);
|
|
88
|
+
const document = Object.keys(root).length ? { ...root, icp: checked.local, humanReview: { reviewedAt: new Date().toISOString(), source: "cli" } } : { company: { domain: normalizedDomain }, icp: checked.local, evidence: [], humanReview: { reviewedAt: new Date().toISOString(), source: "cli" } };
|
|
89
|
+
const result = await writeHostedArtifact({ kind: "icp", key, label: checked.local.name, domain: normalizedDomain, document, expectedRevision: current?.revision ?? 0, changeSummary });
|
|
90
|
+
if (result.status === "saved")
|
|
91
|
+
markIcpSynced(icpPath, domain, { artifactId: result.artifactId, revision: result.revision, documentSha256: result.documentSha256 }, checked.local);
|
|
92
|
+
return { status: result.status, result, checked };
|
|
93
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { auditSnapshot, defaultPolicy } from "./audit.ts";
|
|
2
2
|
export { DEFAULT_ICP_DERIVATION_MODEL, OPENROUTER_API_BASE, deriveWebsiteIcp, normalizeCompanyWebsite, websiteText, icpReviewSegments, type WebsiteIcpDerivation, type WebsiteIcpEvidence, type IcpReviewSegment, type IcpDerivationProgress, } from "./icpDerive.ts";
|
|
3
|
+
export { artifactKeyForDomain, classifyIcpSync, extractHostedIcp, getIcpSyncStatus, icpSha256, markIcpSynced, pushIcp, readIcpSyncState, sidecarPathFor, type IcpSyncState, type IcpSyncStatus, } from "./icpSync.ts";
|
|
3
4
|
export { acquireCheckpointId, acquireCheckpointsDir, createFileAcquireCheckpointStore, validateAcquireCheckpoint, validateAcquireCheckpointKey, type AcquireCheckpoint, type AcquireCheckpointKey, type AcquireCheckpointStore, type AcquireContinuation, } from "./acquireCheckpoint.ts";
|
|
4
5
|
export { matchesTerritory, parseAssignmentPolicy, resolveAssignment, type AssignmentContext, type AssignmentPolicy, type AssignmentResult, type AssignmentStrategy, type TerritoryRule, } from "./assign.ts";
|
|
5
6
|
export { buildBulkUpdatePlan, isFilterableField, parseWhere, type BulkUpdateOptions } from "./bulkUpdate.ts";
|
|
@@ -27,6 +28,7 @@ export { claimHostedPlanApply, hostedPlanDigest, hostedReviewDocument, readHoste
|
|
|
27
28
|
export { scaffoldWorkspace, starterEnrichConfig, starterIcp, starterPlaybook, type InitProvider, type InitSource, type ScaffoldFile, type ScaffoldOptions, } from "./init.ts";
|
|
28
29
|
export { appendCoverage, classifyAccount, classifyCoverage, computeCoverage, coverageCountsFromSnapshot, coveredAccounts, coverageToText, crmCheckableCriteria, deriveAcvFromClosedWon, deriveBuyersPerAccount, estimateTam, loadTamModel, projectEta, readCoverageTimeline, saveTamModel, tamDir, tamReportToMarkdown, type AccountTamClass, type AcvBasis, type DerivedAcv, type DerivedBuyers, type EstimateTamInput, type TamClassified, type TamCoverage, type TamCoverageCounts, type TamCrossCheck, type TamEta, type TamModel, type TamTargeting, type TamUniverse, } from "./tam.ts";
|
|
29
30
|
export { apolloPullKeysForAppend, apolloPullKeysForRefresh, createApolloClient, pullApolloRecords, type ApolloClient, type ApolloClientOptions, type ApolloPullKey, type ApolloPullResult, } from "./enrichApollo.ts";
|
|
31
|
+
export { createZoomInfoClient, pullZoomInfoRecords, type ZoomInfoClient, type ZoomInfoClientOptions, type ZoomInfoCommandResult, type ZoomInfoCommandRunner, type ZoomInfoPullKey, type ZoomInfoPullOptions, type ZoomInfoPullResult, } from "./enrichZoomInfo.ts";
|
|
30
32
|
export { diffFindings, diffSnapshots, diffToMarkdown, type CollectionDiff, type FieldChange, type FindingsDrift, type RecordChange, type SnapshotDiff, } from "./diff.ts";
|
|
31
33
|
export { mergeSnapshots, type MergeConflict, type MergeMatch, type MergeReport, type MergeSuggestion, } from "./merge.ts";
|
|
32
34
|
export { createFilePlanStore, type PlanStore, type StoredPlan } from "./planStore.ts";
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { auditSnapshot, defaultPolicy } from "./audit.js";
|
|
2
2
|
export { DEFAULT_ICP_DERIVATION_MODEL, OPENROUTER_API_BASE, deriveWebsiteIcp, normalizeCompanyWebsite, websiteText, icpReviewSegments, } from "./icpDerive.js";
|
|
3
|
+
export { artifactKeyForDomain, classifyIcpSync, extractHostedIcp, getIcpSyncStatus, icpSha256, markIcpSynced, pushIcp, readIcpSyncState, sidecarPathFor, } from "./icpSync.js";
|
|
3
4
|
export { acquireCheckpointId, acquireCheckpointsDir, createFileAcquireCheckpointStore, validateAcquireCheckpoint, validateAcquireCheckpointKey, } from "./acquireCheckpoint.js";
|
|
4
5
|
export { matchesTerritory, parseAssignmentPolicy, resolveAssignment, } from "./assign.js";
|
|
5
6
|
export { buildBulkUpdatePlan, isFilterableField, parseWhere } from "./bulkUpdate.js";
|
|
@@ -27,6 +28,7 @@ export { claimHostedPlanApply, hostedPlanDigest, hostedReviewDocument, readHoste
|
|
|
27
28
|
export { scaffoldWorkspace, starterEnrichConfig, starterIcp, starterPlaybook, } from "./init.js";
|
|
28
29
|
export { appendCoverage, classifyAccount, classifyCoverage, computeCoverage, coverageCountsFromSnapshot, coveredAccounts, coverageToText, crmCheckableCriteria, deriveAcvFromClosedWon, deriveBuyersPerAccount, estimateTam, loadTamModel, projectEta, readCoverageTimeline, saveTamModel, tamDir, tamReportToMarkdown, } from "./tam.js";
|
|
29
30
|
export { apolloPullKeysForAppend, apolloPullKeysForRefresh, createApolloClient, pullApolloRecords, } from "./enrichApollo.js";
|
|
31
|
+
export { createZoomInfoClient, pullZoomInfoRecords, } from "./enrichZoomInfo.js";
|
|
30
32
|
export { diffFindings, diffSnapshots, diffToMarkdown, } from "./diff.js";
|
|
31
33
|
export { mergeSnapshots, } from "./merge.js";
|
|
32
34
|
export { createFilePlanStore } from "./planStore.js";
|
package/dist/runReport.js
CHANGED
|
@@ -85,6 +85,10 @@ let inflightHeartbeat = null;
|
|
|
85
85
|
* commands simply never stream.
|
|
86
86
|
*/
|
|
87
87
|
export function beginRunReport(args, startedAt) {
|
|
88
|
+
counts = undefined;
|
|
89
|
+
findings = undefined;
|
|
90
|
+
crm = undefined;
|
|
91
|
+
events.length = 0;
|
|
88
92
|
lastHeartbeatAt = 0;
|
|
89
93
|
heartbeatBroker = undefined;
|
|
90
94
|
inflightHeartbeat = null;
|
|
@@ -186,6 +190,13 @@ export async function flushRunReport(args, status, startedAt, error) {
|
|
|
186
190
|
const identity = runIdentity(args, startedAt);
|
|
187
191
|
if (!identity)
|
|
188
192
|
return;
|
|
193
|
+
// A successful command with no result, finding, event, or live progress is
|
|
194
|
+
// terminal telemetry rather than something a person can explore. Keep it
|
|
195
|
+
// out of Runs. Errors always report; heartbeating commands still send their
|
|
196
|
+
// terminal status so an in-progress row cannot be stranded.
|
|
197
|
+
const hasUsefulOutput = Boolean((counts && Object.keys(counts).length > 0) || findings?.length || events.length);
|
|
198
|
+
if (status === "success" && !hasUsefulOutput && lastHeartbeatAt === 0)
|
|
199
|
+
return;
|
|
189
200
|
const broker = getCredential("broker");
|
|
190
201
|
if (!broker?.baseUrl || !broker.accessToken)
|
|
191
202
|
return; // opt-in: only when paired
|
package/docs/api.md
CHANGED
|
@@ -126,7 +126,7 @@ Four flags name "where data comes from / goes to"; they are not interchangeable:
|
|
|
126
126
|
| Flag | Meaning | Values |
|
|
127
127
|
|---|---|---|
|
|
128
128
|
| `--provider` | The CRM the data lives in — the system a snapshot is read from and an approved plan is applied to. | `hubspot`, `salesforce` (plus `stripe`, read-only) |
|
|
129
|
-
| `--source` | The external data source feeding a verb: an enrichment/discovery vendor on `enrich`/`tam` (`--source apollo`, `acquire --source pipe0`), a staged-ingest label on `enrich ingest`, on `signals fetch` which no-auth ATS board adapters to scan, or `exa` on `signals discover`. | `apollo`, `clay`, `pipe0`, `explorium`, `theirstack`, `linkedin` (HeyReach), `exa`; `greenhouse` / `lever` / `ashby` on `signals fetch` |
|
|
129
|
+
| `--source` | The external data source feeding a verb: an enrichment/discovery vendor on `enrich`/`tam` (`--source zoominfo`, `--source apollo`, `acquire --source pipe0`), a staged-ingest label on `enrich ingest`, on `signals fetch` which no-auth ATS board adapters to scan, or `exa` on `signals discover`. | `zoominfo` (official `gtm` CLI), `apollo`, `clay`, `pipe0`, `explorium`, `theirstack`, `linkedin` (HeyReach), `exa`; `greenhouse` / `lever` / `ashby` on `signals fetch` |
|
|
130
130
|
| `--connector` | A signal-intake source connector on `signals fetch`: pulls candidate signals from a connected platform or the local webhook spool into the signal ledger. | `file`, `serpapi-news`, `hubspot-forms` |
|
|
131
131
|
| `--channel` | Where a plan's output is delivered. On `apply`, the delivery terminus — a plan applies to `--provider <crm>` *or* `--channel outbox` (render approved openers to a local outbox file; transmits nothing), never both. On `draft`, which outreach channel the opener is drafted for (shapes the emitted op). | `apply`: `outbox` · `draft`: `email`, `linkedin`, `task` |
|
|
132
132
|
|
package/docs/architecture.md
CHANGED
|
@@ -103,6 +103,11 @@ replays automatically: reconcile provider state, then `plans recover ...
|
|
|
103
103
|
reconciliation. Review documents are immutable/hash-bound; hosted approval
|
|
104
104
|
becomes executable only after the CLI verifies it and generates local HMAC
|
|
105
105
|
signatures. Hosted never owns the apply lease for CLI-origin plans.
|
|
106
|
+
- `hostedArtifacts.ts` + `icpSync.ts` — version-aware artifact transport and
|
|
107
|
+
conservative bidirectional ICP reconciliation. Published revisions use
|
|
108
|
+
compare-and-swap; a private sidecar binds a local ICP hash to its last hosted
|
|
109
|
+
revision. Divergent arrays are never auto-merged and hosted changes never
|
|
110
|
+
silently replace the execution-local ICP file.
|
|
106
111
|
- `assign.ts` — `AssignmentPolicy` (fixed / round-robin / territory /
|
|
107
112
|
account-owner): the pure owner-routing rule `buildAcquirePlan` stamps onto new
|
|
108
113
|
leads (never born ownerless) and `reassign --assign-unowned` reuses to backfill.
|
package/llms.txt
CHANGED
|
@@ -149,8 +149,9 @@ approve → apply.
|
|
|
149
149
|
|
|
150
150
|
## Key invariants (enrich)
|
|
151
151
|
|
|
152
|
-
`fullstackgtm enrich` is governed enrichment: `append` pulls
|
|
153
|
-
via `login apollo`/APOLLO_API_KEY) or
|
|
152
|
+
`fullstackgtm enrich` is governed enrichment: `append` pulls from Apollo (BYO key
|
|
153
|
+
via `login apollo`/APOLLO_API_KEY) or ZoomInfo (official `gtm` CLI; `gtm auth login`),
|
|
154
|
+
or reads data staged by `ingest` (Clay CSV
|
|
154
155
|
exports / webhook payload JSON), matches source records to CRM records via
|
|
155
156
|
ordered keys in `enrich.config.json` (unique hit wins; ambiguity skips or
|
|
156
157
|
becomes `requires_human_record_selection` placeholders — never a coin flip),
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fullstackgtm",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Open-source
|
|
3
|
+
"version": "0.58.0",
|
|
4
|
+
"description": "Open-source CRM control plane and safety toolbox for AI agents: deterministic audits, reviewable patch plans, approval-gated write-back, conflict detection, and entity resolution for HubSpot and Salesforce.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Full Stack GTM LLC <ryan@fullstackgtm.com> (https://fullstackgtm.com)",
|
|
7
7
|
"homepage": "https://github.com/fullstackgtm/core#readme",
|
package/src/cli/enrich.ts
CHANGED
|
@@ -19,7 +19,8 @@ import { progressReporter, reportCounts, reportEvent } from "../runReport.ts";
|
|
|
19
19
|
import { ACQUIRE_STAGES, composeListeners, createProgressEmitter } from "../progress.ts";
|
|
20
20
|
import { createLinkedInProvider, discoverLinkedInProspects } from "../acquireLinkedIn.ts";
|
|
21
21
|
import { clayPeopleFilterRoutes, fitThreshold, icpToClayInvestmentCompanyFilters, icpToClayPeopleFilters, icpToCrustdataFilters, icpToExploriumFilters, scoreProspectAgainstIcp, type Icp } from "../icp.ts";
|
|
22
|
-
import { apolloPullKeysForAppend, apolloPullKeysForRefresh, createApolloClient, pullApolloRecords, type ApolloPullKey } from "../enrichApollo.ts";
|
|
22
|
+
import { apolloPullKeysForAppend, apolloPullKeysForRefresh, createApolloClient, pullApolloRecords, type ApolloPullKey, type ApolloPullOptions } from "../enrichApollo.ts";
|
|
23
|
+
import { createZoomInfoClient, pullZoomInfoRecords } from "../enrichZoomInfo.ts";
|
|
23
24
|
import type { CanonicalGtmSnapshot, CreateRecordPayload } from "../types.ts";
|
|
24
25
|
import { isSpoolPath, readSpoolPath } from "../spoolFiles.ts";
|
|
25
26
|
import { isOptionValue, loadIcp, numericOption, option, readSnapshot, saveRequested } from "./shared.ts";
|
|
@@ -28,11 +29,13 @@ import { unknownSubcommandError } from "./suggest.ts";
|
|
|
28
29
|
import { box, colorEnabled, createProgressRenderer, createStatusLine, formatBar, formatDuration, paint, scoreColor, truncateToWidth, type Paint } from "./ui.ts";
|
|
29
30
|
import { compactPlan, verbosePlanRequested } from "./planOutput.ts";
|
|
30
31
|
import type { AcquireBudget } from "../acquireMeter.ts";
|
|
32
|
+
import { writeHostedArtifact } from "../hostedArtifacts.ts";
|
|
33
|
+
import { readIcpSyncState } from "../icpSync.ts";
|
|
31
34
|
|
|
32
35
|
|
|
33
36
|
/**
|
|
34
|
-
* The enrich layer: governed append/refresh of third-party data (Apollo
|
|
35
|
-
* Clay ingest) into the CRM through the normal dry-run → approval → apply
|
|
37
|
+
* The enrich layer: governed append/refresh of third-party data (Apollo or
|
|
38
|
+
* ZoomInfo pull, Clay ingest) into the CRM through the normal dry-run → approval → apply
|
|
36
39
|
* contract. State lives in the profile-scoped run store (checkpoint,
|
|
37
40
|
* staleness ledger, observability in one); scheduling belongs to the
|
|
38
41
|
* horizontal scheduler — enrich owns no cron logic.
|
|
@@ -75,8 +78,9 @@ and leaves them unassigned. Backfill existing ownerless records with
|
|
|
75
78
|
\`reassign --assign-unowned --to <ownerId>\`.
|
|
76
79
|
|
|
77
80
|
append pulls from an api source (Apollo — BYO key via \`login apollo\` or
|
|
78
|
-
APOLLO_API_KEY
|
|
79
|
-
|
|
81
|
+
APOLLO_API_KEY; ZoomInfo — official \`gtm\` CLI via \`gtm auth login\`) or reads
|
|
82
|
+
data staged by \`enrich ingest\` (Clay CSV exports, webhook payload JSON),
|
|
83
|
+
matches source records to CRM records via the ordered
|
|
80
84
|
match keys in enrich.config.json (unique hit wins; zero hits falls through to
|
|
81
85
|
the next key; multiple hits skip or flow into the suggest chain, per
|
|
82
86
|
onAmbiguous), and emits a fill-blanks-only patch plan. Without --save it
|
|
@@ -259,6 +263,7 @@ are phase 2. Recurring execution is the scheduler's job; enrich has no cron.`);
|
|
|
259
263
|
// piped) and, via the composed reporter, heartbeat to a paired hosted app.
|
|
260
264
|
// The meter reading (creates vs headroom + budget burn) rides the same
|
|
261
265
|
// emitter, feeding the dashboard's gauge without printing anything new.
|
|
266
|
+
const acquireRunLabel = option(rest, "--run-label") ?? `acquire-${source}-${today}`;
|
|
262
267
|
let result: ReturnType<typeof buildAcquirePlan>;
|
|
263
268
|
try {
|
|
264
269
|
acquireProgress.stage(ACQUIRE_STAGES[2], 2, ACQUIRE_STAGES.length);
|
|
@@ -275,7 +280,7 @@ are phase 2. Recurring execution is the scheduler's job; enrich has no cron.`);
|
|
|
275
280
|
source,
|
|
276
281
|
snapshot,
|
|
277
282
|
records,
|
|
278
|
-
runLabel:
|
|
283
|
+
runLabel: acquireRunLabel,
|
|
279
284
|
maxRecords: cap,
|
|
280
285
|
progress: acquireProgress,
|
|
281
286
|
});
|
|
@@ -293,7 +298,7 @@ are phase 2. Recurring execution is the scheduler's job; enrich has no cron.`);
|
|
|
293
298
|
// Observability: headline metrics for the web run timeline (paired users).
|
|
294
299
|
reportCounts({
|
|
295
300
|
sourced: result.counts.fetched,
|
|
296
|
-
|
|
301
|
+
proposed: result.counts.created,
|
|
297
302
|
withheldByMeter: result.counts.withheldByMeter,
|
|
298
303
|
skippedInCrm: apiSkippedCrm,
|
|
299
304
|
skippedSeen: apiSkippedSeen,
|
|
@@ -302,6 +307,16 @@ are phase 2. Recurring execution is the scheduler's job; enrich has no cron.`);
|
|
|
302
307
|
|
|
303
308
|
const meterLine = formatAcquireMeter(headroom, costPerRecord);
|
|
304
309
|
const gaugeLine = acquireGaugeLine(headroom, config.acquire.budget ?? {}, paint(colorEnabled(process.stdout)));
|
|
310
|
+
const icpPath = resolve(process.cwd(), option(rest, "--icp") ?? "icp.json");
|
|
311
|
+
const trackedIcp = existsSync(icpPath) ? readIcpSyncState(icpPath) : null;
|
|
312
|
+
const leadMirror = await writeHostedArtifact({
|
|
313
|
+
kind: "lead_run", key: `leads:${result.plan.id}`, label: acquireRunLabel,
|
|
314
|
+
domain: trackedIcp?.domain,
|
|
315
|
+
document: { runLabel: acquireRunLabel, createdAt: new Date().toISOString(), source, targetDomain: option(rest, "--company-domain"), counts: result.counts,
|
|
316
|
+
plan: result.plan, icpRef: trackedIcp ? { artifactId: trackedIcp.artifactId, domain: trackedIcp.domain, revision: trackedIcp.revision, localIcpSha256: trackedIcp.localIcpSha256 } : undefined },
|
|
317
|
+
});
|
|
318
|
+
if (leadMirror.status === "saved") console.error(`Recorded lead preview against${trackedIcp ? ` ICP revision ${trackedIcp.revision}` : " the local untracked ICP"}.`);
|
|
319
|
+
else if (leadMirror.status === "unavailable") console.error(`Warning: ${leadMirror.reason}. The local lead preview is unchanged.`);
|
|
305
320
|
if (!save) {
|
|
306
321
|
printAcquireOutput({
|
|
307
322
|
args: rest,
|
|
@@ -424,10 +439,19 @@ are phase 2. Recurring execution is the scheduler's job; enrich has no cron.`);
|
|
|
424
439
|
);
|
|
425
440
|
return;
|
|
426
441
|
}
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
442
|
+
if (source !== "apollo" && source !== "zoominfo") {
|
|
443
|
+
throw new Error(
|
|
444
|
+
`enrich ${mode}: api source "${source}" supports acquire discovery, not snapshot enrichment. ` +
|
|
445
|
+
"Use apollo or zoominfo for append/refresh, or stage records with `enrich ingest`.",
|
|
446
|
+
);
|
|
447
|
+
}
|
|
448
|
+
const apolloClient = source === "apollo"
|
|
449
|
+
? createApolloClient({
|
|
450
|
+
getApiKey: () => apolloApiKey(),
|
|
451
|
+
apiBaseUrl: process.env.APOLLO_API_BASE_URL,
|
|
452
|
+
})
|
|
453
|
+
: null;
|
|
454
|
+
const zoomInfoClient = source === "zoominfo" ? createZoomInfoClient() : null;
|
|
431
455
|
if (save) {
|
|
432
456
|
run = await openEnrichRun(store, source, mode, option(rest, "--run-label"), today);
|
|
433
457
|
if (run.cursor) {
|
|
@@ -443,7 +467,7 @@ are phase 2. Recurring execution is the scheduler's job; enrich has no cron.`);
|
|
|
443
467
|
let pullProcessed = 0;
|
|
444
468
|
let result: Awaited<ReturnType<typeof pullApolloRecords>>;
|
|
445
469
|
try {
|
|
446
|
-
|
|
470
|
+
const pullOptions: ApolloPullOptions = {
|
|
447
471
|
resumeAfter: run?.cursor ?? null,
|
|
448
472
|
onProgress: async (progress) => {
|
|
449
473
|
if (pullBar.active) {
|
|
@@ -461,7 +485,10 @@ are phase 2. Recurring execution is the scheduler's job; enrich has no cron.`);
|
|
|
461
485
|
if (progress.miss) run.missedKeys = [...(run.missedKeys ?? []), progress.miss.value];
|
|
462
486
|
await store.update(run);
|
|
463
487
|
},
|
|
464
|
-
}
|
|
488
|
+
};
|
|
489
|
+
result = source === "zoominfo"
|
|
490
|
+
? await pullZoomInfoRecords(zoomInfoClient!, pullKeys, pullOptions)
|
|
491
|
+
: await pullApolloRecords(apolloClient!, pullKeys, pullOptions);
|
|
465
492
|
} finally {
|
|
466
493
|
pullBar.done();
|
|
467
494
|
}
|
package/src/cli/help.ts
CHANGED
|
@@ -90,7 +90,7 @@ Usage:
|
|
|
90
90
|
fullstackgtm enrich refresh [--source apollo] [--stale-days <n>] [--save] [--config <path>] [source options]
|
|
91
91
|
fullstackgtm enrich ingest <file.csv|payload.json|spool.jsonl|spool-dir> --source clay [--run-label <label>]
|
|
92
92
|
fullstackgtm enrich status [--runs] [--source <id>] [--json]
|
|
93
|
-
governed enrichment: pull (Apollo) or stage (Clay) third-party
|
|
93
|
+
governed enrichment: pull (Apollo/ZoomInfo) or stage (Clay) third-party
|
|
94
94
|
data, match it to CRM records deterministically, and emit a
|
|
95
95
|
fill-blanks-only patch plan through the normal dry-run →
|
|
96
96
|
approve → apply gate. refresh re-checks stale stamped fields
|
|
@@ -524,7 +524,7 @@ export const HELP: Record<string, HelpEntry> = {
|
|
|
524
524
|
seeAlso: ["enrich", "plans", "apply", "resolve"],
|
|
525
525
|
},
|
|
526
526
|
enrich: {
|
|
527
|
-
summary: "governed third-party enrichment (Apollo/Clay), fill-blanks-only",
|
|
527
|
+
summary: "governed third-party enrichment (Apollo/ZoomInfo/Clay), fill-blanks-only",
|
|
528
528
|
phase: "Remediate",
|
|
529
529
|
synopsis: ["fullstackgtm enrich append|refresh|ingest|status … (run `enrich --help` for full options)"],
|
|
530
530
|
detail:
|
|
@@ -701,14 +701,14 @@ export const COMMAND_FLAGS: Record<string, string[]> = {
|
|
|
701
701
|
merge: ["--input", "--out", "--json"],
|
|
702
702
|
market: ["--category", "--config", "--vendor", "--snapshot", "--task-account", "--task-deal", "--capture-run", "--run", "--prior-run", "--diff", "--from", "--calls", "--anchor", "--min-mentions", "--max-claims", "--promote-lift", "--model", "--format", "--auto", "--unverified", "--save", "--dry-run", "--verbose", "--json", "--out"],
|
|
703
703
|
tam: [...SOURCE_FLAGS, "--source", "--name", "--icp", "--accounts", "--acv", "--acv-basis", "--acv-from-crm", "--deal-period", "--buyers-per-account", "--cross-checks", "--max", "--max-credits", "--usd-per-credit", "--dry-run", "--confirm", "--cron", "--label", "--save", "--verbose", "--json", "--out"],
|
|
704
|
-
icp: [...SOURCE_FLAGS, "--name", "--icp", "--domain", "--no-interactive", "--signals-from", "--with-history", "--prompt", "--min-score", "--from-judge", "--golden", "--against-outcomes", "--min-accuracy", "--model", "--label", "--save", "--verbose", "--json", "--out"],
|
|
704
|
+
icp: [...SOURCE_FLAGS, "--name", "--icp", "--domain", "--no-interactive", "--signals-from", "--with-history", "--prompt", "--min-score", "--from-judge", "--golden", "--against-outcomes", "--min-accuracy", "--model", "--label", "--change-summary", "--force", "--save", "--verbose", "--json", "--out"],
|
|
705
705
|
signals: ["--bucket", "--source", "--connector", "--connector-opt", "--watchlist", "--keywords", "--from", "--label", "--since", "--icp", "--max-accounts", "--max-results", "--max-searches", "--max-usd", "--account", "--contact", "--unjudged", "--touch", "--result", "--save", "--verbose", "--json", "--explain"],
|
|
706
706
|
draft: ["--from-judge", "--min-score", "--prompt", "--model", "--channel", "--save", "--dry-run", "--verbose", "--json", "--out"],
|
|
707
707
|
schedule: ["--cron", "--label", "--provider", "--trigger", "--timer", "--runs", "--verbose", "--json"],
|
|
708
708
|
};
|
|
709
709
|
|
|
710
710
|
export const FLAGS_WITH_VALUES = new Set([
|
|
711
|
-
"--account", "--account-id", "--accounts", "--acv", "--acv-basis", "--after", "--anchor", "--api-key", "--approve", "--archive", "--assign-owner", "--attendees", "--before", "--bucket", "--buyers-per-account", "--call", "--call-type", "--calls", "--capture-run", "--category", "--channel", "--client", "--client-id", "--client-secret", "--company-domain", "--config", "--connector", "--connector-opt", "--contact", "--cron", "--cross-checks", "--deal", "--deal-period", "--diff", "--domain", "--email", "--except-deal-stage", "--format", "--from", "--from-judge", "--golden", "--guard", "--icp", "--in", "--input", "--instance-url", "--keep", "--key", "--keywords", "--label", "--list", "--login-url", "--match", "--match-property", "--max", "--max-accounts", "--max-claims", "--max-credits", "--max-examples", "--max-operations", "--max-results", "--max-searches", "--max-usd", "--min-accuracy", "--min-confidence", "--min-mentions", "--min-score", "--model", "--name", "--objects", "--operations", "--out", "--pipeline", "--plan", "--plan-id", "--policy", "--port", "--prepared-by", "--prior-run", "--profile", "--promote-lift", "--prompt", "--provider", "--reason", "--require", "--result", "--rubric", "--rule", "--rules", "--run", "--run-label", "--runs", "--scan-limit", "--scopes", "--seed", "--set", "--signals-from", "--since", "--snapshot", "--source", "--staged-run", "--stale-days", "--status", "--task-account", "--task-deal", "--timer", "--title", "--to", "--today", "--token", "--token-env", "--touch", "--transcript", "--trigger", "--usd-per-credit", "--value", "--values-from", "--vendor", "--via", "--watchlist", "--where",
|
|
711
|
+
"--account", "--account-id", "--accounts", "--acv", "--acv-basis", "--after", "--anchor", "--api-key", "--approve", "--archive", "--assign-owner", "--attendees", "--before", "--bucket", "--buyers-per-account", "--call", "--call-type", "--calls", "--capture-run", "--category", "--change-summary", "--channel", "--client", "--client-id", "--client-secret", "--company-domain", "--config", "--connector", "--connector-opt", "--contact", "--cron", "--cross-checks", "--deal", "--deal-period", "--diff", "--domain", "--email", "--except-deal-stage", "--format", "--from", "--from-judge", "--golden", "--guard", "--icp", "--in", "--input", "--instance-url", "--keep", "--key", "--keywords", "--label", "--list", "--login-url", "--match", "--match-property", "--max", "--max-accounts", "--max-claims", "--max-credits", "--max-examples", "--max-operations", "--max-results", "--max-searches", "--max-usd", "--min-accuracy", "--min-confidence", "--min-mentions", "--min-score", "--model", "--name", "--objects", "--operations", "--out", "--pipeline", "--plan", "--plan-id", "--policy", "--port", "--prepared-by", "--prior-run", "--profile", "--promote-lift", "--prompt", "--provider", "--reason", "--require", "--result", "--rubric", "--rule", "--rules", "--run", "--run-label", "--runs", "--scan-limit", "--scopes", "--seed", "--set", "--signals-from", "--since", "--snapshot", "--source", "--staged-run", "--stale-days", "--status", "--task-account", "--task-deal", "--timer", "--title", "--to", "--today", "--token", "--token-env", "--touch", "--transcript", "--trigger", "--usd-per-credit", "--value", "--values-from", "--vendor", "--via", "--watchlist", "--where",
|
|
712
712
|
]);
|
|
713
713
|
|
|
714
714
|
// Lifecycle-grouped front door. One line per verb, organized by the
|