@f-o-h/cli 0.1.75 → 0.1.77
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/foh.js
CHANGED
|
@@ -10050,10 +10050,21 @@ var SERVICE_TOKEN_ENV = "FOH_SERVICE_TOKEN";
|
|
|
10050
10050
|
var ORG_ID_ENV = "FOH_ORG_ID";
|
|
10051
10051
|
var API_URL_ENV = "FOH_API_URL";
|
|
10052
10052
|
var TOKEN_EXPIRES_AT_ENV = "FOH_TOKEN_EXPIRES_AT";
|
|
10053
|
+
var SERVICE_TOKEN_ENV_ALIAS = "FOH_EXTERNAL_AGENT_EVAL_TOKEN";
|
|
10054
|
+
var ORG_ID_ENV_ALIAS = "FOH_EXTERNAL_AGENT_EVAL_ORG_ID";
|
|
10055
|
+
var API_URL_ENV_ALIAS = "FOH_EXTERNAL_AGENT_EVAL_API_URL";
|
|
10056
|
+
var TOKEN_EXPIRES_AT_ENV_ALIAS = "FOH_EXTERNAL_AGENT_EVAL_TOKEN_EXPIRES_AT";
|
|
10053
10057
|
function normalizeEnv(value) {
|
|
10054
10058
|
const normalized = String(value ?? "").trim();
|
|
10055
10059
|
return normalized ? normalized : void 0;
|
|
10056
10060
|
}
|
|
10061
|
+
function firstDefinedEnv(env, keys) {
|
|
10062
|
+
for (const key of keys) {
|
|
10063
|
+
const value = normalizeEnv(env[key]);
|
|
10064
|
+
if (value) return value;
|
|
10065
|
+
}
|
|
10066
|
+
return void 0;
|
|
10067
|
+
}
|
|
10057
10068
|
function decodeBase64UrlJson(value) {
|
|
10058
10069
|
try {
|
|
10059
10070
|
const padded = value.replace(/-/g, "+").replace(/_/g, "/").padEnd(Math.ceil(value.length / 4) * 4, "=");
|
|
@@ -10083,25 +10094,25 @@ function credentialExpiresSoon(expiresAt, minimumTtlMs = 0, now = Date.now()) {
|
|
|
10083
10094
|
return remainingMs !== null && remainingMs <= minimumTtlMs;
|
|
10084
10095
|
}
|
|
10085
10096
|
function credentialsFromEnv(apiUrlOverride, env = process.env) {
|
|
10086
|
-
const token =
|
|
10097
|
+
const token = firstDefinedEnv(env, [SERVICE_TOKEN_ENV, SERVICE_TOKEN_ENV_ALIAS]);
|
|
10087
10098
|
if (!token) return void 0;
|
|
10088
|
-
const apiUrl = resolveApiUrlOverride(apiUrlOverride) ??
|
|
10089
|
-
const orgId =
|
|
10099
|
+
const apiUrl = resolveApiUrlOverride(apiUrlOverride) ?? firstDefinedEnv(env, [API_URL_ENV, API_URL_ENV_ALIAS]) ?? DEFAULT_FOH_API_URL;
|
|
10100
|
+
const orgId = firstDefinedEnv(env, [ORG_ID_ENV, ORG_ID_ENV_ALIAS]);
|
|
10090
10101
|
return {
|
|
10091
10102
|
apiUrl,
|
|
10092
10103
|
token,
|
|
10093
|
-
expiresAt:
|
|
10104
|
+
expiresAt: firstDefinedEnv(env, [TOKEN_EXPIRES_AT_ENV, TOKEN_EXPIRES_AT_ENV_ALIAS]) ?? expiryFromJwt(token) ?? fallbackExpiry(),
|
|
10094
10105
|
...isUsableOrgId(orgId) ? { orgId } : {}
|
|
10095
10106
|
};
|
|
10096
10107
|
}
|
|
10097
10108
|
function hasEnvCredentials(env = process.env) {
|
|
10098
|
-
return Boolean(
|
|
10109
|
+
return Boolean(firstDefinedEnv(env, [SERVICE_TOKEN_ENV, SERVICE_TOKEN_ENV_ALIAS]));
|
|
10099
10110
|
}
|
|
10100
10111
|
function loadCredentials(apiUrlOverride) {
|
|
10101
10112
|
const envCreds = credentialsFromEnv(apiUrlOverride);
|
|
10102
10113
|
if (envCreds) {
|
|
10103
10114
|
if (credentialExpiresSoon(envCreds.expiresAt)) {
|
|
10104
|
-
throw new Error("Token expired. Refresh FOH_SERVICE_TOKEN/FOH_TOKEN_EXPIRES_AT or run: foh auth login");
|
|
10115
|
+
throw new Error("Token expired. Refresh FOH_SERVICE_TOKEN/FOH_TOKEN_EXPIRES_AT (or FOH_EXTERNAL_AGENT_EVAL_TOKEN/FOH_EXTERNAL_AGENT_EVAL_TOKEN_EXPIRES_AT) or run: foh auth login");
|
|
10105
10116
|
}
|
|
10106
10117
|
return envCreds;
|
|
10107
10118
|
}
|
|
@@ -14461,56 +14472,66 @@ async function validateAgentLocalDraftShape(agentId, opts = {}) {
|
|
|
14461
14472
|
warnings: ["local-only draft-shape validation was used"]
|
|
14462
14473
|
});
|
|
14463
14474
|
}
|
|
14464
|
-
function
|
|
14465
|
-
|
|
14466
|
-
|
|
14467
|
-
|
|
14468
|
-
|
|
14469
|
-
|
|
14470
|
-
|
|
14471
|
-
|
|
14472
|
-
if (!opts.breakGlassReason || !opts.breakGlassIncident) {
|
|
14473
|
-
throw new FohError({
|
|
14474
|
-
step: "agent.publish",
|
|
14475
|
-
error: "Both --break-glass-reason and --break-glass-incident are required together",
|
|
14476
|
-
remediation: "Provide both break-glass fields, or omit both for normal publish.",
|
|
14477
|
-
statusCode: 400
|
|
14478
|
-
});
|
|
14479
|
-
}
|
|
14480
|
-
const data2 = await apiFetch(`/v1/console/agents/${opts.agent}/publish`, {
|
|
14481
|
-
method: "POST",
|
|
14482
|
-
body: JSON.stringify({
|
|
14483
|
-
break_glass: {
|
|
14484
|
-
reason: String(opts.breakGlassReason),
|
|
14485
|
-
incident_id: String(opts.breakGlassIncident)
|
|
14486
|
-
}
|
|
14487
|
-
}),
|
|
14488
|
-
orgId: opts.org,
|
|
14489
|
-
apiUrlOverride: opts.apiUrl
|
|
14475
|
+
async function publishAgentAction(opts) {
|
|
14476
|
+
if (opts.breakGlassReason || opts.breakGlassIncident) {
|
|
14477
|
+
if (!opts.breakGlassReason || !opts.breakGlassIncident) {
|
|
14478
|
+
throw new FohError({
|
|
14479
|
+
step: "agent.publish",
|
|
14480
|
+
error: "Both --break-glass-reason and --break-glass-incident are required together",
|
|
14481
|
+
remediation: "Provide both break-glass fields, or omit both for normal publish.",
|
|
14482
|
+
statusCode: 400
|
|
14490
14483
|
});
|
|
14491
|
-
format({
|
|
14492
|
-
status: "published_with_break_glass",
|
|
14493
|
-
warning: "break-glass bypassed the normal validate -> publish evidence gate CLI sequence",
|
|
14494
|
-
publish: data2
|
|
14495
|
-
}, { json: opts.json ?? false });
|
|
14496
|
-
return;
|
|
14497
14484
|
}
|
|
14498
|
-
const
|
|
14499
|
-
|
|
14485
|
+
const data2 = await apiFetch(`/v1/console/agents/${opts.agent}/publish`, {
|
|
14486
|
+
method: "POST",
|
|
14487
|
+
body: JSON.stringify({
|
|
14488
|
+
break_glass: {
|
|
14489
|
+
reason: String(opts.breakGlassReason),
|
|
14490
|
+
incident_id: String(opts.breakGlassIncident)
|
|
14491
|
+
}
|
|
14492
|
+
}),
|
|
14500
14493
|
orgId: opts.org,
|
|
14501
|
-
apiUrlOverride: opts.apiUrl
|
|
14502
|
-
certMode: opts.certMode,
|
|
14503
|
-
scenarioIds: opts.certScenarioIds,
|
|
14504
|
-
adaptiveRuns: Number(opts.certAdaptiveRuns),
|
|
14505
|
-
maxImprovementRounds: Number(opts.certMaxImprovementRounds)
|
|
14494
|
+
apiUrlOverride: opts.apiUrl
|
|
14506
14495
|
});
|
|
14507
14496
|
format({
|
|
14508
|
-
status: "
|
|
14509
|
-
|
|
14510
|
-
publish:
|
|
14497
|
+
status: "published_with_break_glass",
|
|
14498
|
+
warning: "break-glass bypassed the normal validate -> publish evidence gate CLI sequence",
|
|
14499
|
+
publish: data2
|
|
14511
14500
|
}, { json: opts.json ?? false });
|
|
14501
|
+
return;
|
|
14502
|
+
}
|
|
14503
|
+
const data = await validateCertifyAndPublishAgent({
|
|
14504
|
+
agentId: opts.agent,
|
|
14505
|
+
orgId: opts.org,
|
|
14506
|
+
apiUrlOverride: opts.apiUrl,
|
|
14507
|
+
certMode: opts.certMode ?? "quick",
|
|
14508
|
+
scenarioIds: opts.certScenarioIds,
|
|
14509
|
+
adaptiveRuns: Number(opts.certAdaptiveRuns ?? "30"),
|
|
14510
|
+
maxImprovementRounds: Number(opts.certMaxImprovementRounds ?? "1")
|
|
14511
|
+
});
|
|
14512
|
+
format({
|
|
14513
|
+
status: "validated_published",
|
|
14514
|
+
certification: data.certification,
|
|
14515
|
+
publish: data.publish
|
|
14516
|
+
}, { json: opts.json ?? false });
|
|
14517
|
+
}
|
|
14518
|
+
function registerAgentPublishCommand(parent, options = {}) {
|
|
14519
|
+
const publish = parent.command("publish").description(options.publicAlias ? "Publish an agent using existing certification evidence" : "Validate and publish an agent using existing certification evidence").requiredOption("--agent <id>", "Agent ID").option("--org <id>", "Org ID (default: stored org from foh org use)").option("--api-url <url>", "API base URL override").option("--json", "Output as JSON");
|
|
14520
|
+
if (!options.publicAlias) {
|
|
14521
|
+
publish.option("--cert-mode <m>", "Deprecated compatibility flag; publish consumes existing certification evidence", "quick").option("--cert-scenario-ids <csv>", "Deprecated compatibility flag; run foh certify before publish").option("--cert-adaptive-runs <n>", "Deprecated compatibility flag; run foh certify before publish", "30").option("--cert-max-improvement-rounds <n>", "Deprecated compatibility flag; run foh certify before publish", "1").option("--break-glass-reason <reason>", "Break-glass reason for publish override").option("--break-glass-incident <id>", "Break-glass incident ID for publish override");
|
|
14522
|
+
}
|
|
14523
|
+
publish.action(async (opts) => withCommandErrorHandling(async () => {
|
|
14524
|
+
await publishAgentAction(opts);
|
|
14512
14525
|
}));
|
|
14513
14526
|
}
|
|
14527
|
+
function registerAgentValidationCommands(agent) {
|
|
14528
|
+
agent.command("validate").description("Validate agent config \u2014 exits 1 if issues found").requiredOption("--agent <id>", "Agent ID").option("--local-only", "Run local draft-shape validation without calling remote validate endpoint").option("--api-url <url>", "API base URL override").option("--json", "Output as JSON").action(async (opts) => withCommandErrorHandling(async () => {
|
|
14529
|
+
const data = opts.localOnly ? await validateAgentLocalDraftShape(opts.agent, { apiUrlOverride: opts.apiUrl }) : await validateAgentRemoteOnly(opts.agent, { apiUrlOverride: opts.apiUrl });
|
|
14530
|
+
format(data, { json: opts.json ?? false });
|
|
14531
|
+
if (Array.isArray(data.issues) && data.issues.length > 0) markCommandFailed(1);
|
|
14532
|
+
}));
|
|
14533
|
+
registerAgentPublishCommand(agent);
|
|
14534
|
+
}
|
|
14514
14535
|
|
|
14515
14536
|
// src/commands/agent.ts
|
|
14516
14537
|
function registerAgent(program3) {
|
|
@@ -14851,6 +14872,72 @@ async function agentExport(agentId, opts = {}) {
|
|
|
14851
14872
|
return manifest;
|
|
14852
14873
|
}
|
|
14853
14874
|
|
|
14875
|
+
// src/lib/template-proof-plan.ts
|
|
14876
|
+
var ACCEPTED_NO_SPEND_VOICE_HOLD_REASONS = [
|
|
14877
|
+
"voice_contact_expected_no_spend_hold",
|
|
14878
|
+
"contact_phone_missing",
|
|
14879
|
+
"voice_contact_phone_provisioning_failed",
|
|
14880
|
+
"paid_resource_blocked_by_spend_policy",
|
|
14881
|
+
"byon_voice_number_not_configured",
|
|
14882
|
+
"provider_capacity_blocked"
|
|
14883
|
+
];
|
|
14884
|
+
function missionForGate(gate) {
|
|
14885
|
+
const command = String(gate.command || "");
|
|
14886
|
+
const channels = gate.channels ?? [];
|
|
14887
|
+
if (command.includes("foh certify run")) return "certification";
|
|
14888
|
+
if (command.includes("--mission widget") || channels.includes("widget")) return "widget";
|
|
14889
|
+
if (command.includes("--mission voice") || channels.includes("voice")) return "voice";
|
|
14890
|
+
return "other";
|
|
14891
|
+
}
|
|
14892
|
+
function concreteCommand(gate, agentId) {
|
|
14893
|
+
const command = String(gate.command || "").trim();
|
|
14894
|
+
return command.replaceAll("<agent_id>", agentId);
|
|
14895
|
+
}
|
|
14896
|
+
function buildTemplateProofPlan(templateResponse, agentId) {
|
|
14897
|
+
const template = templateResponse.template ?? {};
|
|
14898
|
+
const contract = template.template_contract ?? {};
|
|
14899
|
+
const templateId = String(contract.template_id || template.id || "");
|
|
14900
|
+
const templateSlug = String(contract.slug || templateId || "unknown-template");
|
|
14901
|
+
const templateName = String(contract.name || template.name || templateSlug);
|
|
14902
|
+
const useCase = String(contract.use_case || "unknown");
|
|
14903
|
+
const proofGates = Array.isArray(contract.proof_gates) ? contract.proof_gates : [];
|
|
14904
|
+
const cloneMode = String(contract.fork_policy?.clone_mode || "unknown");
|
|
14905
|
+
const commands = proofGates.filter((gate) => typeof gate.command === "string" && gate.command.trim().length > 0).map((gate) => {
|
|
14906
|
+
const mission = missionForGate(gate);
|
|
14907
|
+
const command = {
|
|
14908
|
+
gate_id: String(gate.id || mission),
|
|
14909
|
+
mission,
|
|
14910
|
+
command: concreteCommand(gate, agentId),
|
|
14911
|
+
expected_status: mission === "voice" ? "pass_or_expected_hold" : "pass",
|
|
14912
|
+
pass_criteria: Array.isArray(gate.pass_criteria) ? gate.pass_criteria.map(String) : []
|
|
14913
|
+
};
|
|
14914
|
+
if (mission === "voice") {
|
|
14915
|
+
command.environment = { FOH_CLI_SPEND_POLICY: "no_spend" };
|
|
14916
|
+
command.accepted_hold_reason_codes = ACCEPTED_NO_SPEND_VOICE_HOLD_REASONS;
|
|
14917
|
+
}
|
|
14918
|
+
return command;
|
|
14919
|
+
});
|
|
14920
|
+
return {
|
|
14921
|
+
schema_version: "template_proof_plan.v1",
|
|
14922
|
+
template_id: templateId,
|
|
14923
|
+
template_slug: templateSlug,
|
|
14924
|
+
template_name: templateName,
|
|
14925
|
+
use_case: useCase,
|
|
14926
|
+
agent_id: agentId,
|
|
14927
|
+
outcome: {
|
|
14928
|
+
primary_outcome: String(contract.outcome_contract?.primary_outcome || ""),
|
|
14929
|
+
required_lead_fields: (contract.outcome_contract?.required_lead_fields ?? []).map(String)
|
|
14930
|
+
},
|
|
14931
|
+
lineage: {
|
|
14932
|
+
source_template_id: templateId,
|
|
14933
|
+
source_template_slug: templateSlug,
|
|
14934
|
+
clone_mode: cloneMode
|
|
14935
|
+
},
|
|
14936
|
+
commands,
|
|
14937
|
+
next_commands: commands.map((entry) => entry.command)
|
|
14938
|
+
};
|
|
14939
|
+
}
|
|
14940
|
+
|
|
14854
14941
|
// src/commands/templates.ts
|
|
14855
14942
|
var VALID_CATEGORIES = ["buyer", "seller", "landlord", "commercial"];
|
|
14856
14943
|
function registerTemplates(program3) {
|
|
@@ -14871,6 +14958,41 @@ function registerTemplates(program3) {
|
|
|
14871
14958
|
const data = await apiFetch(`/v1/console/templates/${opts.template}`, { apiUrlOverride: opts.apiUrl });
|
|
14872
14959
|
format(data, { json: opts.json ?? false });
|
|
14873
14960
|
}));
|
|
14961
|
+
templates.command("capabilities").description("Show machine-readable template capabilities for planning (delivery, tools, voice options, proof gates)").requiredOption("--template <id>", "Template ID").option("--api-url <url>", "API base URL override").option("--json", "Output as JSON").action(async (opts) => withCommandErrorHandling(async () => {
|
|
14962
|
+
const data = await apiFetch(`/v1/console/templates/${opts.template}/capabilities`, { apiUrlOverride: opts.apiUrl });
|
|
14963
|
+
format(data, { json: opts.json ?? false });
|
|
14964
|
+
}));
|
|
14965
|
+
templates.command("recipe").description("Show machine-readable recipe bundle for coding-agent customization (editable paths, guardrails, verification commands)").requiredOption("--template <id>", "Template ID").option("--org <id>", "Org ID (default: stored org from foh org use)").option("--api-url <url>", "API base URL override").option("--json", "Output as JSON").action(async (opts) => withCommandErrorHandling(async () => {
|
|
14966
|
+
const data = await apiFetch(`/v1/console/templates/${opts.template}/recipe`, {
|
|
14967
|
+
orgId: opts.org,
|
|
14968
|
+
apiUrlOverride: opts.apiUrl
|
|
14969
|
+
});
|
|
14970
|
+
format(data, { json: opts.json ?? false });
|
|
14971
|
+
}));
|
|
14972
|
+
templates.command("select").description("Select candidate templates from a business requirement brief").requiredOption("--brief <json|@file>", "Business requirement brief JSON or @path").option("--api-url <url>", "API base URL override").option("--json", "Output as JSON").action(async (opts) => withCommandErrorHandling(async () => {
|
|
14973
|
+
const brief = await parseJsonOption(opts.brief, "--brief");
|
|
14974
|
+
const data = await apiFetch("/v1/console/templates/select", {
|
|
14975
|
+
method: "POST",
|
|
14976
|
+
body: JSON.stringify(brief),
|
|
14977
|
+
apiUrlOverride: opts.apiUrl
|
|
14978
|
+
});
|
|
14979
|
+
format(data, { json: opts.json ?? false });
|
|
14980
|
+
}));
|
|
14981
|
+
templates.command("fork").description("Fork a system template into a customer template with explicit lineage and contract diff").requiredOption("--template <id>", "Source template ID").requiredOption("--name <name>", "Forked template name").option("--description <text>", "Fork description").option("--category <c>", "Fork category override").option("--contract <json|@file>", "Optional contract patch JSON or @path").option("--org <id>", "Org ID (default: stored org from foh org use)").option("--api-url <url>", "API base URL override").option("--json", "Output as JSON").action(async (opts) => withCommandErrorHandling(async () => {
|
|
14982
|
+
const payload = {
|
|
14983
|
+
name: opts.name
|
|
14984
|
+
};
|
|
14985
|
+
if (opts.description) payload.description = opts.description;
|
|
14986
|
+
if (opts.category) payload.category = opts.category;
|
|
14987
|
+
if (opts.contract) payload.contract = await parseJsonOption(opts.contract, "--contract");
|
|
14988
|
+
const data = await apiFetch(`/v1/console/templates/${opts.template}/fork`, {
|
|
14989
|
+
method: "POST",
|
|
14990
|
+
body: JSON.stringify(payload),
|
|
14991
|
+
orgId: opts.org,
|
|
14992
|
+
apiUrlOverride: opts.apiUrl
|
|
14993
|
+
});
|
|
14994
|
+
format(data, { json: opts.json ?? false });
|
|
14995
|
+
}));
|
|
14874
14996
|
templates.command("apply").description("Create a new agent in your org from a template (clones draft config, leaves unpublished unless --publish)").requiredOption("--template <id>", "Template ID").requiredOption("--name <name>", "Name for the new agent").option("--org <id>", "Org ID (default: stored org from foh org use)").option("--publish", "Validate and publish using existing certification evidence after creating").option("--cert-mode <m>", "Deprecated compatibility flag; run foh sim certify before publish", "full").option("--cert-adaptive-runs <n>", "Deprecated compatibility flag; run foh sim certify before publish", "30").option("--cert-max-improvement-rounds <n>", "Deprecated compatibility flag; run foh sim certify before publish", "1").option("--api-url <url>", "API base URL override").option("--json", "Output as JSON").action(async (opts) => withCommandErrorHandling(async () => {
|
|
14875
14997
|
const result = await apiFetch(`/v1/console/templates/${opts.template}/apply`, {
|
|
14876
14998
|
method: "POST",
|
|
@@ -14902,6 +15024,73 @@ function registerTemplates(program3) {
|
|
|
14902
15024
|
});
|
|
14903
15025
|
format({ status: "created_and_published", agent: result.agent, publish: published }, { json: opts.json ?? false });
|
|
14904
15026
|
}));
|
|
15027
|
+
templates.command("proof-plan").description("Expand a template proof contract into concrete prove/certify commands for an applied agent").requiredOption("--template <id>", "Template ID").requiredOption("--agent <id>", "Applied agent ID").option("--api-url <url>", "API base URL override").option("--json", "Output as JSON").action(async (opts) => withCommandErrorHandling(async () => {
|
|
15028
|
+
const data = await apiFetch(`/v1/console/templates/${opts.template}/proof-plan`, {
|
|
15029
|
+
method: "POST",
|
|
15030
|
+
body: JSON.stringify({ agent_id: opts.agent }),
|
|
15031
|
+
apiUrlOverride: opts.apiUrl
|
|
15032
|
+
});
|
|
15033
|
+
if (data?.plan) {
|
|
15034
|
+
format(data.plan, { json: opts.json ?? false });
|
|
15035
|
+
return;
|
|
15036
|
+
}
|
|
15037
|
+
const fallbackTemplate = await apiFetch(`/v1/console/templates/${opts.template}`, { apiUrlOverride: opts.apiUrl });
|
|
15038
|
+
const fallbackPlan = buildTemplateProofPlan(fallbackTemplate, opts.agent);
|
|
15039
|
+
format(fallbackPlan, { json: opts.json ?? false });
|
|
15040
|
+
}));
|
|
15041
|
+
templates.command("prove").description("Template-aware prove helper that derives missions from template proof gates (no manual mission inference)").requiredOption("--template <id>", "Template ID").requiredOption("--agent <id>", "Applied agent ID").option("--mode <mode>", "Prove mode: quick (widget+voice) or full (includes certification)", "quick").option("--api-url <url>", "API base URL override").option("--json", "Output as JSON").action(async (opts) => withCommandErrorHandling(async () => {
|
|
15042
|
+
const mode = String(opts.mode || "quick").toLowerCase();
|
|
15043
|
+
if (mode !== "quick" && mode !== "full") {
|
|
15044
|
+
throw new FohError({
|
|
15045
|
+
step: "templates.prove",
|
|
15046
|
+
error: `Invalid mode: ${opts.mode}`,
|
|
15047
|
+
remediation: "Use --mode quick or --mode full"
|
|
15048
|
+
});
|
|
15049
|
+
}
|
|
15050
|
+
const data = await apiFetch(`/v1/console/templates/${opts.template}/proof-plan`, {
|
|
15051
|
+
method: "POST",
|
|
15052
|
+
body: JSON.stringify({ agent_id: opts.agent }),
|
|
15053
|
+
apiUrlOverride: opts.apiUrl
|
|
15054
|
+
});
|
|
15055
|
+
const plan = data.plan;
|
|
15056
|
+
const commands = Array.isArray(plan?.commands) ? plan.commands : [];
|
|
15057
|
+
const selected = commands.filter((entry) => mode === "full" ? true : entry?.mission === "widget" || entry?.mission === "voice");
|
|
15058
|
+
format({
|
|
15059
|
+
schema_version: "template_prove_helper.v1",
|
|
15060
|
+
template_id: plan?.template_id ?? opts.template,
|
|
15061
|
+
agent_id: opts.agent,
|
|
15062
|
+
mode,
|
|
15063
|
+
commands: selected,
|
|
15064
|
+
next_commands: selected.map((entry) => entry.command)
|
|
15065
|
+
}, { json: opts.json ?? false });
|
|
15066
|
+
}));
|
|
15067
|
+
templates.command("publish").description("Template-aware publish helper that validates evidence before agent publish").requiredOption("--template <id>", "Template ID").requiredOption("--agent <id>", "Applied agent ID").requiredOption("--evidence <json|@file>", "Template publish evidence JSON or @path").option("--org <id>", "Org ID (default: stored org from foh org use)").option("--dry-run", "Only validate evidence and return publish decision").option("--api-url <url>", "API base URL override").option("--json", "Output as JSON").action(async (opts) => withCommandErrorHandling(async () => {
|
|
15068
|
+
const evidence = await parseJsonOption(opts.evidence, "--evidence");
|
|
15069
|
+
const helper = await apiFetch(`/v1/console/templates/${opts.template}/publish-helper`, {
|
|
15070
|
+
method: "POST",
|
|
15071
|
+
body: JSON.stringify({
|
|
15072
|
+
agent_id: opts.agent,
|
|
15073
|
+
evidence
|
|
15074
|
+
}),
|
|
15075
|
+
orgId: opts.org,
|
|
15076
|
+
apiUrlOverride: opts.apiUrl
|
|
15077
|
+
});
|
|
15078
|
+
if (opts.dryRun) {
|
|
15079
|
+
format(helper, { json: opts.json ?? false });
|
|
15080
|
+
return;
|
|
15081
|
+
}
|
|
15082
|
+
const publish = await apiFetch(`/v1/console/agents/${opts.agent}/publish`, {
|
|
15083
|
+
method: "POST",
|
|
15084
|
+
body: JSON.stringify({}),
|
|
15085
|
+
orgId: opts.org,
|
|
15086
|
+
apiUrlOverride: opts.apiUrl
|
|
15087
|
+
});
|
|
15088
|
+
format({
|
|
15089
|
+
status: "template_publish_completed",
|
|
15090
|
+
helper,
|
|
15091
|
+
publish
|
|
15092
|
+
}, { json: opts.json ?? false });
|
|
15093
|
+
}));
|
|
14905
15094
|
}
|
|
14906
15095
|
|
|
14907
15096
|
// src/commands/widget.ts
|
|
@@ -15469,7 +15658,7 @@ async function resolveWhatsAppSetupInputs(opts) {
|
|
|
15469
15658
|
if (!appSecret) process.stdout.write("App Secret is required.\n");
|
|
15470
15659
|
}
|
|
15471
15660
|
if (opts.audioEnabled === void 0 && process.stdin.isTTY && process.stdout.isTTY && !opts.json) {
|
|
15472
|
-
const answer = await promptLine("Enable WhatsApp audio fallback
|
|
15661
|
+
const answer = await promptLine("Enable inbound WhatsApp audio fallback auto-reply? [Y/n]", { allowEmpty: true });
|
|
15473
15662
|
audioEnabled = isAffirmative(answer, true);
|
|
15474
15663
|
}
|
|
15475
15664
|
return {
|
|
@@ -15692,7 +15881,7 @@ function registerWhatsAppChannelCommands(whatsapp, addCommonOptions) {
|
|
|
15692
15881
|
}));
|
|
15693
15882
|
addCommonOptions(
|
|
15694
15883
|
whatsapp.command("setup").description("Run guided WhatsApp setup and readiness checks")
|
|
15695
|
-
).option("--phone-number-id <id>", "Meta WhatsApp phone number id").option("--access-token <token>", "Meta access token").option("--verify-token <token>", "Webhook verify token").option("--app-secret <secret>", "Meta app secret for signature verification").option("--agent-id <id>", "Agent to bind to the WhatsApp channel").option("--audio-enabled <bool>", "Enable WhatsApp audio fallback
|
|
15884
|
+
).option("--phone-number-id <id>", "Meta WhatsApp phone number id").option("--access-token <token>", "Meta access token").option("--verify-token <token>", "Webhook verify token").option("--app-secret <secret>", "Meta app secret for signature verification").option("--agent-id <id>", "Agent to bind to the WhatsApp channel").option("--audio-enabled <bool>", "Enable inbound WhatsApp audio fallback auto-reply (true/false)").option("--generate-verify-token", "Generate webhook verify token automatically when missing").option("--wizard", "Run guided setup wizard prompts").action(async (opts) => withCommandErrorHandling(async () => {
|
|
15696
15885
|
const inputs = await resolveWhatsAppSetupInputs(opts);
|
|
15697
15886
|
const creds = loadCredentials(opts.apiUrl);
|
|
15698
15887
|
const apiBaseUrl = creds.apiUrl;
|
|
@@ -15785,7 +15974,7 @@ function registerWhatsAppChannelCommands(whatsapp, addCommonOptions) {
|
|
|
15785
15974
|
}));
|
|
15786
15975
|
addCommonOptions(
|
|
15787
15976
|
whatsapp.command("connect").description("Connect WhatsApp channel credentials")
|
|
15788
|
-
).requiredOption("--phone-number-id <id>", "Meta WhatsApp phone number id").requiredOption("--access-token <token>", "Meta access token").option("--agent-id <id>", "Agent to bind to the WhatsApp channel").option("--verify-token <token>", "Webhook verify token").option("--app-secret <secret>", "Meta app secret for signature verification").option("--audio-enabled <bool>", "Enable WhatsApp audio fallback
|
|
15977
|
+
).requiredOption("--phone-number-id <id>", "Meta WhatsApp phone number id").requiredOption("--access-token <token>", "Meta access token").option("--agent-id <id>", "Agent to bind to the WhatsApp channel").option("--verify-token <token>", "Webhook verify token").option("--app-secret <secret>", "Meta app secret for signature verification").option("--audio-enabled <bool>", "Enable inbound WhatsApp audio fallback auto-reply (true/false)", "true").action(async (opts) => withCommandErrorHandling(async () => {
|
|
15789
15978
|
const data = await apiFetch("/v1/console/channels/whatsapp/connect", {
|
|
15790
15979
|
method: "POST",
|
|
15791
15980
|
body: JSON.stringify({
|
|
@@ -32798,7 +32987,7 @@ var StdioServerTransport = class {
|
|
|
32798
32987
|
};
|
|
32799
32988
|
|
|
32800
32989
|
// src/lib/cli-version.ts
|
|
32801
|
-
var CLI_VERSION = "0.1.
|
|
32990
|
+
var CLI_VERSION = "0.1.77";
|
|
32802
32991
|
|
|
32803
32992
|
// src/commands/mcp-serve.ts
|
|
32804
32993
|
var DEFAULT_TIMEOUT_MS = 12e4;
|
|
@@ -36463,7 +36652,27 @@ function registerTest(program3) {
|
|
|
36463
36652
|
}));
|
|
36464
36653
|
}
|
|
36465
36654
|
|
|
36466
|
-
// src/commands/ops.ts
|
|
36655
|
+
// src/commands/ops-agency-setup.ts
|
|
36656
|
+
function registerOpsAgencySetupCommands(reporting) {
|
|
36657
|
+
reporting.command("agency-setup-preview").description("Build a fail-closed setup/release/customer-evidence preview from agency name and official source URL").requiredOption("--agency-name <name>", "Estate agency trading name").option("--source-url <url>", "Official branch/contact/source URL").option("--branch-location <value>", "Branch/location this setup represents").option("--tools <csv>", "Requested tool surfaces", "widget,voice,email,callback,calendar,crm,webhook,whatsapp").option("--target-mode <value>", "Target exposure mode", "founder_assisted").option("--org <id>", "Org ID (default: stored org from foh org use)").option("--api-url <url>", "API base URL override").option("--json", "Output as JSON").action(async (opts) => withCommandErrorHandling(async () => {
|
|
36658
|
+
const body = {
|
|
36659
|
+
agency_name: String(opts.agencyName),
|
|
36660
|
+
requested_tool_surface: parseCsvOption(opts.tools) ?? [],
|
|
36661
|
+
target_exposure_mode: String(opts.targetMode)
|
|
36662
|
+
};
|
|
36663
|
+
if (opts.sourceUrl) body.source_url = String(opts.sourceUrl);
|
|
36664
|
+
if (opts.branchLocation) body.branch_location = String(opts.branchLocation);
|
|
36665
|
+
const data = await apiFetch("/v1/console/agency-setup/preview", {
|
|
36666
|
+
method: "POST",
|
|
36667
|
+
body: JSON.stringify(body),
|
|
36668
|
+
orgId: opts.org,
|
|
36669
|
+
apiUrlOverride: opts.apiUrl
|
|
36670
|
+
});
|
|
36671
|
+
format(data, { json: opts.json ?? false });
|
|
36672
|
+
}));
|
|
36673
|
+
}
|
|
36674
|
+
|
|
36675
|
+
// src/commands/ops-diagnostics.ts
|
|
36467
36676
|
function parseClientErrorSource(raw) {
|
|
36468
36677
|
if (!raw) return void 0;
|
|
36469
36678
|
const source = String(raw).trim().toLowerCase();
|
|
@@ -36477,8 +36686,44 @@ function parseClientErrorSource(raw) {
|
|
|
36477
36686
|
statusCode: 400
|
|
36478
36687
|
});
|
|
36479
36688
|
}
|
|
36480
|
-
function
|
|
36481
|
-
const
|
|
36689
|
+
function registerOpsIntegrationCommands(ops) {
|
|
36690
|
+
const integrations = ops.command("integrations").description("Integration diagnostics and health checks");
|
|
36691
|
+
integrations.command("health-check").description("Run integration health-check probes for an agent").requiredOption("--agent <id>", "Agent ID").option("--integration-id <id>", "Optional integration filter: crm_webhook|calendar_sync|automation_webhook").option("--api-url <url>", "API base URL override").option("--json", "Output as JSON").action(async (opts) => withCommandErrorHandling(async () => {
|
|
36692
|
+
const body = {};
|
|
36693
|
+
if (opts.integrationId) body.integration_id = String(opts.integrationId);
|
|
36694
|
+
const data = await apiFetch(`/v1/console/agents/${opts.agent}/integrations/health-check`, {
|
|
36695
|
+
method: "POST",
|
|
36696
|
+
body: JSON.stringify(body),
|
|
36697
|
+
apiUrlOverride: opts.apiUrl
|
|
36698
|
+
});
|
|
36699
|
+
format(data, { json: opts.json ?? false });
|
|
36700
|
+
}));
|
|
36701
|
+
}
|
|
36702
|
+
function registerOpsClientErrorCommands(ops) {
|
|
36703
|
+
const clientErrors = ops.command("client-errors").description("Client error telemetry and ingestion");
|
|
36704
|
+
clientErrors.command("report").description("Submit a client error packet").requiredOption("--message <text>", "Error message").option("--stack <text>", "Error stack trace").option("--component-stack <text>", "React component stack").option("--url <url>", "Document URL").option("--route <route>", "Application route").option("--user-agent <text>", "Browser user-agent override").option("--source <value>", "Error source: window|react|unhandledrejection").option("--org <id>", "Org ID (default: stored org from foh org use)").option("--api-url <url>", "API base URL override").option("--json", "Output as JSON").action(async (opts) => withCommandErrorHandling(async () => {
|
|
36705
|
+
const source = parseClientErrorSource(opts.source);
|
|
36706
|
+
const body = {
|
|
36707
|
+
message: String(opts.message)
|
|
36708
|
+
};
|
|
36709
|
+
if (opts.stack) body.stack = String(opts.stack);
|
|
36710
|
+
if (opts.componentStack) body.componentStack = String(opts.componentStack);
|
|
36711
|
+
if (opts.url) body.url = String(opts.url);
|
|
36712
|
+
if (opts.route) body.route = String(opts.route);
|
|
36713
|
+
if (opts.userAgent) body.userAgent = String(opts.userAgent);
|
|
36714
|
+
if (source) body.source = source;
|
|
36715
|
+
const data = await apiFetch("/v1/console/client-errors", {
|
|
36716
|
+
method: "POST",
|
|
36717
|
+
body: JSON.stringify(body),
|
|
36718
|
+
orgId: opts.org,
|
|
36719
|
+
apiUrlOverride: opts.apiUrl
|
|
36720
|
+
});
|
|
36721
|
+
format(data, { json: opts.json ?? false });
|
|
36722
|
+
}));
|
|
36723
|
+
}
|
|
36724
|
+
|
|
36725
|
+
// src/commands/ops-incidents.ts
|
|
36726
|
+
function registerOpsIncidentCommands(ops) {
|
|
36482
36727
|
const incidents = ops.command("incidents").description("Incident loop operations");
|
|
36483
36728
|
incidents.command("list").description("List incidents for current org").option("--state <value>", "Incident state filter").option("--agent <id>", "Agent ID filter").option("--limit <n>", "Max rows (1-200)", "50").option("--org <id>", "Org ID (default: stored org from foh org use)").option("--api-url <url>", "API base URL override").option("--json", "Output as JSON").action(async (opts) => withCommandErrorHandling(async () => {
|
|
36484
36729
|
const params = new URLSearchParams();
|
|
@@ -36530,6 +36775,8 @@ function registerOps(program3) {
|
|
|
36530
36775
|
});
|
|
36531
36776
|
format(data, { json: opts.json ?? false });
|
|
36532
36777
|
}));
|
|
36778
|
+
}
|
|
36779
|
+
function registerOpsRecommendationCommands(ops) {
|
|
36533
36780
|
const recommendations = ops.command("recommendations").description("Recommendation queue operations");
|
|
36534
36781
|
recommendations.command("list").description("List recommendations for current org").option("--status <value>", "Recommendation status").option("--limit <n>", "Max rows (1-200)", "50").option("--org <id>", "Org ID (default: stored org from foh org use)").option("--api-url <url>", "API base URL override").option("--json", "Output as JSON").action(async (opts) => withCommandErrorHandling(async () => {
|
|
36535
36782
|
const params = new URLSearchParams();
|
|
@@ -36579,84 +36826,10 @@ function registerOps(program3) {
|
|
|
36579
36826
|
});
|
|
36580
36827
|
format(data, { json: opts.json ?? false });
|
|
36581
36828
|
}));
|
|
36582
|
-
|
|
36583
|
-
|
|
36584
|
-
|
|
36585
|
-
|
|
36586
|
-
if (opts.conversation) params.set("conversationId", String(opts.conversation));
|
|
36587
|
-
params.set("limit", String(parsePositiveInt(opts.limit, 100, 1, 200)));
|
|
36588
|
-
const data = await apiFetch(withQuery("/v1/console/traces", params), {
|
|
36589
|
-
orgId: opts.org,
|
|
36590
|
-
apiUrlOverride: opts.apiUrl
|
|
36591
|
-
});
|
|
36592
|
-
format(data, { json: opts.json ?? false });
|
|
36593
|
-
}));
|
|
36594
|
-
traces.command("replay").description("Replay a trace input in dry-run mode").requiredOption("--trace <id>", "Trace ID").option("--org <id>", "Org ID (default: stored org from foh org use)").option("--api-url <url>", "API base URL override").option("--json", "Output as JSON").action(async (opts) => withCommandErrorHandling(async () => {
|
|
36595
|
-
const data = await apiFetch(`/v1/console/traces/${opts.trace}/replay`, {
|
|
36596
|
-
method: "POST",
|
|
36597
|
-
body: JSON.stringify({}),
|
|
36598
|
-
orgId: opts.org,
|
|
36599
|
-
apiUrlOverride: opts.apiUrl
|
|
36600
|
-
});
|
|
36601
|
-
format(data, { json: opts.json ?? false });
|
|
36602
|
-
}));
|
|
36603
|
-
const testingOs = ops.command("testing-os").description("Testing OS lane and coverage diagnostics");
|
|
36604
|
-
testingOs.command("lane-health").description("Show Testing OS lane-health summary").requiredOption("--agent <id>", "Agent ID").option("--window-days <n>", "Lookback window (1-90 days)", "7").option("--api-url <url>", "API base URL override").option("--json", "Output as JSON").action(async (opts) => withCommandErrorHandling(async () => {
|
|
36605
|
-
const params = new URLSearchParams({
|
|
36606
|
-
windowDays: String(parsePositiveInt(opts.windowDays, 7, 1, 90))
|
|
36607
|
-
});
|
|
36608
|
-
const data = await apiFetch(withQuery(`/v1/console/agents/${opts.agent}/testing-os/lane-health`, params), {
|
|
36609
|
-
apiUrlOverride: opts.apiUrl
|
|
36610
|
-
});
|
|
36611
|
-
format(data, { json: opts.json ?? false });
|
|
36612
|
-
}));
|
|
36613
|
-
testingOs.command("fingerprints").description("Show Testing OS failure fingerprints").requiredOption("--agent <id>", "Agent ID").option("--window-days <n>", "Lookback window (1-120 days)", "30").option("--api-url <url>", "API base URL override").option("--json", "Output as JSON").action(async (opts) => withCommandErrorHandling(async () => {
|
|
36614
|
-
const params = new URLSearchParams({
|
|
36615
|
-
windowDays: String(parsePositiveInt(opts.windowDays, 30, 1, 120))
|
|
36616
|
-
});
|
|
36617
|
-
const data = await apiFetch(withQuery(`/v1/console/agents/${opts.agent}/testing-os/fingerprints`, params), {
|
|
36618
|
-
apiUrlOverride: opts.apiUrl
|
|
36619
|
-
});
|
|
36620
|
-
format(data, { json: opts.json ?? false });
|
|
36621
|
-
}));
|
|
36622
|
-
testingOs.command("coverage-matrix").description("Show Testing OS coverage matrix baseline/current delta").requiredOption("--agent <id>", "Agent ID").option("--api-url <url>", "API base URL override").option("--json", "Output as JSON").action(async (opts) => withCommandErrorHandling(async () => {
|
|
36623
|
-
const data = await apiFetch(`/v1/console/agents/${opts.agent}/testing-os/coverage-matrix`, {
|
|
36624
|
-
apiUrlOverride: opts.apiUrl
|
|
36625
|
-
});
|
|
36626
|
-
format(data, { json: opts.json ?? false });
|
|
36627
|
-
}));
|
|
36628
|
-
const integrations = ops.command("integrations").description("Integration diagnostics and health checks");
|
|
36629
|
-
integrations.command("health-check").description("Run integration health-check probes for an agent").requiredOption("--agent <id>", "Agent ID").option("--integration-id <id>", "Optional integration filter: crm_webhook|calendar_sync|automation_webhook").option("--api-url <url>", "API base URL override").option("--json", "Output as JSON").action(async (opts) => withCommandErrorHandling(async () => {
|
|
36630
|
-
const body = {};
|
|
36631
|
-
if (opts.integrationId) body.integration_id = String(opts.integrationId);
|
|
36632
|
-
const data = await apiFetch(`/v1/console/agents/${opts.agent}/integrations/health-check`, {
|
|
36633
|
-
method: "POST",
|
|
36634
|
-
body: JSON.stringify(body),
|
|
36635
|
-
apiUrlOverride: opts.apiUrl
|
|
36636
|
-
});
|
|
36637
|
-
format(data, { json: opts.json ?? false });
|
|
36638
|
-
}));
|
|
36639
|
-
const clientErrors = ops.command("client-errors").description("Client error telemetry and ingestion");
|
|
36640
|
-
clientErrors.command("report").description("Submit a client error packet").requiredOption("--message <text>", "Error message").option("--stack <text>", "Error stack trace").option("--component-stack <text>", "React component stack").option("--url <url>", "Document URL").option("--route <route>", "Application route").option("--user-agent <text>", "Browser user-agent override").option("--source <value>", "Error source: window|react|unhandledrejection").option("--org <id>", "Org ID (default: stored org from foh org use)").option("--api-url <url>", "API base URL override").option("--json", "Output as JSON").action(async (opts) => withCommandErrorHandling(async () => {
|
|
36641
|
-
const source = parseClientErrorSource(opts.source);
|
|
36642
|
-
const body = {
|
|
36643
|
-
message: String(opts.message)
|
|
36644
|
-
};
|
|
36645
|
-
if (opts.stack) body.stack = String(opts.stack);
|
|
36646
|
-
if (opts.componentStack) body.componentStack = String(opts.componentStack);
|
|
36647
|
-
if (opts.url) body.url = String(opts.url);
|
|
36648
|
-
if (opts.route) body.route = String(opts.route);
|
|
36649
|
-
if (opts.userAgent) body.userAgent = String(opts.userAgent);
|
|
36650
|
-
if (source) body.source = source;
|
|
36651
|
-
const data = await apiFetch("/v1/console/client-errors", {
|
|
36652
|
-
method: "POST",
|
|
36653
|
-
body: JSON.stringify(body),
|
|
36654
|
-
orgId: opts.org,
|
|
36655
|
-
apiUrlOverride: opts.apiUrl
|
|
36656
|
-
});
|
|
36657
|
-
format(data, { json: opts.json ?? false });
|
|
36658
|
-
}));
|
|
36659
|
-
const reporting = ops.command("reporting").description("Reporting aggregates and release evidence");
|
|
36829
|
+
}
|
|
36830
|
+
|
|
36831
|
+
// src/commands/ops-reporting.ts
|
|
36832
|
+
function registerOpsReportingCommands(reporting) {
|
|
36660
36833
|
reporting.command("kb-usage").description("Show KB usage aggregate report").requiredOption("--agent <id>", "Agent ID").option("--days <n>", "Lookback window in days", "7").option("--org <id>", "Org ID (default: stored org from foh org use)").option("--api-url <url>", "API base URL override").option("--json", "Output as JSON").action(async (opts) => withCommandErrorHandling(async () => {
|
|
36661
36834
|
const params = new URLSearchParams({
|
|
36662
36835
|
agentId: String(opts.agent),
|
|
@@ -36702,6 +36875,36 @@ function registerOps(program3) {
|
|
|
36702
36875
|
});
|
|
36703
36876
|
format(data, { json: opts.json ?? false });
|
|
36704
36877
|
}));
|
|
36878
|
+
reporting.command("launch-packet").description("Show latest customer launch packet and grouped go-live blockers").option("--environment <value>", "Environment filter").option("--org <id>", "Org ID (default: stored org from foh org use)").option("--api-url <url>", "API base URL override").option("--json", "Output as JSON").action(async (opts) => withCommandErrorHandling(async () => {
|
|
36879
|
+
const params = new URLSearchParams();
|
|
36880
|
+
if (opts.environment) params.set("environment", String(opts.environment));
|
|
36881
|
+
const data = await apiFetch(withQuery("/v1/console/release-launch-packet", params), {
|
|
36882
|
+
orgId: opts.org,
|
|
36883
|
+
apiUrlOverride: opts.apiUrl
|
|
36884
|
+
});
|
|
36885
|
+
format(data, { json: opts.json ?? false });
|
|
36886
|
+
}));
|
|
36887
|
+
reporting.command("launch-packet-skeletons").description("Generate customer launch evidence skeletons from latest launch packet blockers").option("--environment <value>", "Environment filter").option("--org <id>", "Org ID (default: stored org from foh org use)").option("--api-url <url>", "API base URL override").option("--json", "Output as JSON").action(async (opts) => withCommandErrorHandling(async () => {
|
|
36888
|
+
const params = new URLSearchParams();
|
|
36889
|
+
if (opts.environment) params.set("environment", String(opts.environment));
|
|
36890
|
+
const data = await apiFetch(withQuery("/v1/console/release-launch-packet/evidence-skeletons", params), {
|
|
36891
|
+
orgId: opts.org,
|
|
36892
|
+
apiUrlOverride: opts.apiUrl
|
|
36893
|
+
});
|
|
36894
|
+
format(data, { json: opts.json ?? false });
|
|
36895
|
+
}));
|
|
36896
|
+
reporting.command("launch-packet-evidence-check").description("Dry-run customer launch evidence before any release gate can consume it").requiredOption("--evidence <json|@file>", 'Evidence JSON object, usually { "evidence": [{ "id": "...", "payload": {...} }] }').option("--apply", "Request apply mode; currently fails closed until evidence storage contract exists").option("--org <id>", "Org ID (default: stored org from foh org use)").option("--api-url <url>", "API base URL override").option("--json", "Output as JSON").action(async (opts) => withCommandErrorHandling(async () => {
|
|
36897
|
+
const parsed = await parseJsonOption(opts.evidence, "--evidence");
|
|
36898
|
+
const body = parsed && typeof parsed === "object" && !Array.isArray(parsed) ? { ...parsed } : { evidence: parsed };
|
|
36899
|
+
if (opts.apply) body.apply = true;
|
|
36900
|
+
const data = await apiFetch("/v1/console/release-launch-packet/evidence-dry-run", {
|
|
36901
|
+
method: "POST",
|
|
36902
|
+
body: JSON.stringify(body),
|
|
36903
|
+
orgId: opts.org,
|
|
36904
|
+
apiUrlOverride: opts.apiUrl
|
|
36905
|
+
});
|
|
36906
|
+
format(data, { json: opts.json ?? false });
|
|
36907
|
+
}));
|
|
36705
36908
|
reporting.command("release-scorecard").description("Show deterministic release scorecard for an agent").requiredOption("--agent <id>", "Agent ID").option("--limit <n>", "Number of runs to include", "10").option("--api-url <url>", "API base URL override").option("--json", "Output as JSON").action(async (opts) => withCommandErrorHandling(async () => {
|
|
36706
36909
|
const limit = Math.max(1, Math.min(100, Number(opts.limit || 10) || 10));
|
|
36707
36910
|
const data = await apiFetch(`/v1/console/agents/${opts.agent}/release-scorecard?limit=${limit}`, {
|
|
@@ -36747,6 +36950,74 @@ function registerOps(program3) {
|
|
|
36747
36950
|
}));
|
|
36748
36951
|
}
|
|
36749
36952
|
|
|
36953
|
+
// src/commands/ops-testing-os.ts
|
|
36954
|
+
function registerOpsTestingOsCommands(ops) {
|
|
36955
|
+
const testingOs = ops.command("testing-os").description("Testing OS lane and coverage diagnostics");
|
|
36956
|
+
testingOs.command("lane-health").description("Show Testing OS lane-health summary").requiredOption("--agent <id>", "Agent ID").option("--window-days <n>", "Lookback window (1-90 days)", "7").option("--api-url <url>", "API base URL override").option("--json", "Output as JSON").action(async (opts) => withCommandErrorHandling(async () => {
|
|
36957
|
+
const params = new URLSearchParams({
|
|
36958
|
+
windowDays: String(parsePositiveInt(opts.windowDays, 7, 1, 90))
|
|
36959
|
+
});
|
|
36960
|
+
const data = await apiFetch(withQuery(`/v1/console/agents/${opts.agent}/testing-os/lane-health`, params), {
|
|
36961
|
+
apiUrlOverride: opts.apiUrl
|
|
36962
|
+
});
|
|
36963
|
+
format(data, { json: opts.json ?? false });
|
|
36964
|
+
}));
|
|
36965
|
+
testingOs.command("fingerprints").description("Show Testing OS failure fingerprints").requiredOption("--agent <id>", "Agent ID").option("--window-days <n>", "Lookback window (1-120 days)", "30").option("--api-url <url>", "API base URL override").option("--json", "Output as JSON").action(async (opts) => withCommandErrorHandling(async () => {
|
|
36966
|
+
const params = new URLSearchParams({
|
|
36967
|
+
windowDays: String(parsePositiveInt(opts.windowDays, 30, 1, 120))
|
|
36968
|
+
});
|
|
36969
|
+
const data = await apiFetch(withQuery(`/v1/console/agents/${opts.agent}/testing-os/fingerprints`, params), {
|
|
36970
|
+
apiUrlOverride: opts.apiUrl
|
|
36971
|
+
});
|
|
36972
|
+
format(data, { json: opts.json ?? false });
|
|
36973
|
+
}));
|
|
36974
|
+
testingOs.command("coverage-matrix").description("Show Testing OS coverage matrix baseline/current delta").requiredOption("--agent <id>", "Agent ID").option("--api-url <url>", "API base URL override").option("--json", "Output as JSON").action(async (opts) => withCommandErrorHandling(async () => {
|
|
36975
|
+
const data = await apiFetch(`/v1/console/agents/${opts.agent}/testing-os/coverage-matrix`, {
|
|
36976
|
+
apiUrlOverride: opts.apiUrl
|
|
36977
|
+
});
|
|
36978
|
+
format(data, { json: opts.json ?? false });
|
|
36979
|
+
}));
|
|
36980
|
+
}
|
|
36981
|
+
|
|
36982
|
+
// src/commands/ops-traces.ts
|
|
36983
|
+
function registerOpsTraceCommands(ops) {
|
|
36984
|
+
const traces = ops.command("traces").description("Observability trace operations");
|
|
36985
|
+
traces.command("list").description("List traces for current org").option("--agent <id>", "Agent ID filter").option("--conversation <id>", "Conversation ID filter").option("--limit <n>", "Max rows (1-200)", "100").option("--org <id>", "Org ID (default: stored org from foh org use)").option("--api-url <url>", "API base URL override").option("--json", "Output as JSON").action(async (opts) => withCommandErrorHandling(async () => {
|
|
36986
|
+
const params = new URLSearchParams();
|
|
36987
|
+
if (opts.agent) params.set("agentId", String(opts.agent));
|
|
36988
|
+
if (opts.conversation) params.set("conversationId", String(opts.conversation));
|
|
36989
|
+
params.set("limit", String(parsePositiveInt(opts.limit, 100, 1, 200)));
|
|
36990
|
+
const data = await apiFetch(withQuery("/v1/console/traces", params), {
|
|
36991
|
+
orgId: opts.org,
|
|
36992
|
+
apiUrlOverride: opts.apiUrl
|
|
36993
|
+
});
|
|
36994
|
+
format(data, { json: opts.json ?? false });
|
|
36995
|
+
}));
|
|
36996
|
+
traces.command("replay").description("Replay a trace input in dry-run mode").requiredOption("--trace <id>", "Trace ID").option("--org <id>", "Org ID (default: stored org from foh org use)").option("--api-url <url>", "API base URL override").option("--json", "Output as JSON").action(async (opts) => withCommandErrorHandling(async () => {
|
|
36997
|
+
const data = await apiFetch(`/v1/console/traces/${opts.trace}/replay`, {
|
|
36998
|
+
method: "POST",
|
|
36999
|
+
body: JSON.stringify({}),
|
|
37000
|
+
orgId: opts.org,
|
|
37001
|
+
apiUrlOverride: opts.apiUrl
|
|
37002
|
+
});
|
|
37003
|
+
format(data, { json: opts.json ?? false });
|
|
37004
|
+
}));
|
|
37005
|
+
}
|
|
37006
|
+
|
|
37007
|
+
// src/commands/ops.ts
|
|
37008
|
+
function registerOps(program3) {
|
|
37009
|
+
const ops = program3.command("ops").description("Operational/reporting workflows (incidents, recommendations, traces, evidence)");
|
|
37010
|
+
registerOpsIncidentCommands(ops);
|
|
37011
|
+
registerOpsRecommendationCommands(ops);
|
|
37012
|
+
registerOpsTraceCommands(ops);
|
|
37013
|
+
registerOpsTestingOsCommands(ops);
|
|
37014
|
+
registerOpsIntegrationCommands(ops);
|
|
37015
|
+
registerOpsClientErrorCommands(ops);
|
|
37016
|
+
const reporting = ops.command("reporting").description("Reporting aggregates and release evidence");
|
|
37017
|
+
registerOpsReportingCommands(reporting);
|
|
37018
|
+
registerOpsAgencySetupCommands(reporting);
|
|
37019
|
+
}
|
|
37020
|
+
|
|
36750
37021
|
// src/commands/diag.ts
|
|
36751
37022
|
function toErrorRecord(error2) {
|
|
36752
37023
|
if (error2 instanceof Error) {
|
|
@@ -41121,6 +41392,11 @@ var DEFAULT_PROMPT_VERSION = "blank-setup.v1";
|
|
|
41121
41392
|
var DEFAULT_BATCH_MODELS = "openai/codex,anthropic/claude,cursor/agent";
|
|
41122
41393
|
var PROMPTS = {
|
|
41123
41394
|
"blank-setup.v1": "Go to https://frontofhouse.okii.uk. Use only public docs, public API docs, and the public npm CLI package. Always invoke the CLI with `npx --yes @f-o-h/cli@latest ...`; do not use unpinned `npx @f-o-h/cli ...`, because cached older packages can produce invalid evidence. Install or verify the FOH CLI, authenticate or reach a deterministic auth blocker, then create or configure a Front Of House voice agent and website widget. Mass evals reuse existing eval state: run `npx --yes @f-o-h/cli@latest org status --json` and `npx --yes @f-o-h/cli@latest agent list --json` before trying to create a fresh agent; if an existing eval agent is present, configure and prove that agent instead of creating a second bronze-tier agent. Prefer the certification-oriented buyer templates: run `npx --yes @f-o-h/cli@latest templates list --category buyer --json` and use `UK Buyer Qualification` or `Viewing Booking` when available; do not use a greeting-only template for proof/certification. Prefer `npx --yes @f-o-h/cli@latest setup --phone-mode observe` for the free scaffold path: agent, widget, voice config, smoke test, certification, and publish readiness together. Treat phone-number purchasing as an explicit paid/scarce contact-path step, not part of high-volume eval setup. If `FOH_CLI_SPEND_POLICY=no_spend` is active and a command returns `paid_resource_blocked_by_spend_policy`, do not try to bypass it; continue widget/setup proof and report that exact reason code for the phone path. If the customer/operator explicitly owns a number and asks for real PSTN proof, use `npx --yes @f-o-h/cli@latest provision byon attach --phone-number <e164> --confirm-owned --json`; do not invent ownership or buy a FOH-owned number. Run proof/smoke/certification where available, including widget proof, voice proof, and one explicit `foh certify run --agent <id> --profile release --json` before publish. `foh prove` does not run release certification by default; only pass `--include-certification --proof-cache-dir .foh/proof-cache` when an explicit combined proof/certification run is required. If voice proof returns `contact_phone_missing` or `voice_contact_expected_no_spend_hold`, report that exact reason code unless a BYON/customer-approved phone path already exists. If `FOH_EXTERNAL_AGENT_RUN_DIR` is set, write `${FOH_EXTERNAL_AGENT_RUN_DIR}/external-agent-metadata.json` with `schema_version`, `docs_pages_used`, key decisions, and blocker reason codes before finishing. Produce a final evidence summary with commands run, docs used, artifacts created, and any blocker reason codes. Do not assume access to the private source repository.",
|
|
41395
|
+
"real-estate-buyer-enquiry.v1": "Go to https://frontofhouse.okii.uk. Use only public docs, public API docs, and the public npm CLI package. Always invoke the CLI with `npx --yes @f-o-h/cli@latest ...`; do not use unpinned `npx @f-o-h/cli ...`. Do not assume access to the private source repository. Mission: configure a buyer-enquiry real-estate agent (UK Buyer Qualification preferred), prove widget behavior, and prove voice behavior in no-spend mode. Required path: 1) verify auth/org scope and reuse existing eval org/agent where possible; 2) select/apply buyer template; 3) configure widget + voice; 4) run widget smoke and `foh certify run --profile release`; 5) run voice proof and treat no-spend contact holds as expected only when all non-contact gates pass. Do not buy numbers; if spend policy blocks purchase, record `paid_resource_blocked_by_spend_policy` and continue no-spend proof path. Final artifact must include: selected template id/slug, commands executed, pass/hold/fail per gate, reason codes, docs_pages_used, and next fix commands.",
|
|
41396
|
+
"real-estate-seller-valuation.v1": "Go to https://frontofhouse.okii.uk. Use only public docs, public API docs, and the public npm CLI package. Always invoke the CLI with `npx --yes @f-o-h/cli@latest ...`; do not use unpinned `npx @f-o-h/cli ...`. Do not assume access to the private source repository. Mission: configure a seller-valuation real-estate agent, prove valuation lead capture on widget and voice, and keep strict no-spend behavior. Required path: 1) verify auth/org scope and reuse existing eval state; 2) select/apply seller valuation template; 3) configure widget + voice; 4) run widget smoke and release certification; 5) run voice proof and classify holds. Do not claim precise valuation output without approved tooling; safe fallback or handoff must remain explicit. Do not buy numbers. Final artifact must include: selected template id/slug, lead fields observed, tool/action behavior, reason codes, docs_pages_used, and next fix commands.",
|
|
41397
|
+
"real-estate-viewing-and-qa.v1": "Go to https://frontofhouse.okii.uk. Use only public docs, public API docs, and the public npm CLI package. Always invoke the CLI with `npx --yes @f-o-h/cli@latest ...`; do not use unpinned `npx @f-o-h/cli ...`. Do not assume access to the private source repository. Mission: configure a viewing-booking/property-QA real-estate agent and prove booking-safe behavior under no-spend policy. Required path: 1) verify auth/org scope and reuse existing eval state; 2) select/apply viewing template; 3) configure widget + voice; 4) run widget smoke, release certification, and voice proof; 5) explicitly check no-duplicate-side-effect behavior and safe fallback/handoff when booking tooling or contact path is unavailable. Do not buy numbers. Final artifact must include: selected template id/slug, booking/fallback evidence, reason codes, docs_pages_used, and next fix commands.",
|
|
41398
|
+
"real-estate-landlord-enquiry.v1": "Go to https://frontofhouse.okii.uk. Use only public docs, public API docs, and the public npm CLI package. Always invoke the CLI with `npx --yes @f-o-h/cli@latest ...`; do not use unpinned `npx @f-o-h/cli ...`. Do not assume access to the private source repository. Mission: configure a landlord-enquiry real-estate agent and prove lead capture + safe escalation under no-spend constraints. Required path: 1) verify auth/org scope and reuse existing eval state; 2) select/apply landlord template; 3) configure widget + voice; 4) run widget smoke, release certification, and voice proof; 5) ensure handoff/escalation remains reason-coded and no-silent-drop. Do not buy numbers. Final artifact must include: selected template id/slug, lead/action/handoff evidence summary, reason codes, docs_pages_used, and next fix commands.",
|
|
41399
|
+
"arbitrary-agency-setup-release.v1": "Go to https://frontofhouse.okii.uk. Use only public docs, public API docs, the deployed production API, and the public npm CLI package. Always invoke the CLI with `npx --yes @f-o-h/cli@latest ...`; do not use unpinned `npx @f-o-h/cli ...`, local source, private repo scripts, or unpublished commands. Do not assume access to the private source repository. Mission: prove whether an arbitrary estate agency can be set up or accurately held using the public launch evidence workflow. Required path: 1) verify CLI version and auth/org scope; 2) run `foh ops reporting agency-setup-preview` with the supplied agency name, official source URL, branch location, requested tool surface, and target mode; 3) run `foh ops reporting launch-packet --json`; 4) run `foh ops reporting launch-packet-skeletons --json`; 5) run `foh ops reporting launch-packet-evidence-check --json` only with redacted synthetic or customer-provided evidence, never raw credentials or secrets; 6) classify the outcome as pass, expected hold, or product failure. No-spend boundary: do not buy phone numbers, provision paid resources, scrape private systems, bypass credential holds, or claim live/customer-ready/production unless the launch packet explicitly allows it. Expected holds such as missing customer credentials, missing behavior approval, missing live voice validation, or missing production signoff are acceptable only when the commands expose clear reason codes and next actions. Final artifact must include commands executed, docs_pages_used, manual_intervention_count, CLI/API version readback, launch mode observed, reason codes, evidence artifacts created, and exact next commands. If `FOH_EXTERNAL_AGENT_RUN_DIR` is set, write `${FOH_EXTERNAL_AGENT_RUN_DIR}/external-agent-metadata.json` with `schema_version`, `docs_pages_used`, key decisions, and blocker reason codes before finishing.",
|
|
41124
41400
|
"debug-proof-failure.v1": "You are given a FOH proof or debug artifact. Use public docs and FOH CLI/API behavior to classify whether the blocker is docs, auth, org setup, agent config, widget, channel, runtime, or product bug. Produce a redacted improvement packet or the exact command needed to produce one. Do not ask the human to interpret logs manually unless no machine-readable artifact exists.",
|
|
41125
41401
|
"knowledge-miss.v1": "A FOH agent failed to answer a business question. Use CLI/API/docs to determine whether this is a knowledge-ingestion issue, retrieval issue, config issue, prompt/behavior issue, or runtime issue. Prefer foh knowledge query, transcript export, replay, and foh bug improve artifacts over screenshots.",
|
|
41126
41402
|
"replay-failure.v1": "You are given a FOH transcript or replay artifact. Use CLI/API/docs to replay or inspect the failed interaction, identify expected vs actual behavior, and produce a scenario-test or improvement-packet candidate."
|
|
@@ -41251,11 +41527,38 @@ function knowledgeMissPromptContext(knowledgeQuestion, expectedAnswer) {
|
|
|
41251
41527
|
"- Do not patch around the miss manually; produce the smallest redacted artifact that explains whether the fix belongs to docs, ingestion, retrieval, config, or runtime."
|
|
41252
41528
|
].join("\n");
|
|
41253
41529
|
}
|
|
41530
|
+
function agencySetupPromptContext(context = {}) {
|
|
41531
|
+
const agencyName = String(context.agencyName || "").trim();
|
|
41532
|
+
const sourceUrl = String(context.sourceUrl || "").trim();
|
|
41533
|
+
const branchLocation = String(context.branchLocation || "").trim();
|
|
41534
|
+
const targetMode = String(context.targetMode || "").trim();
|
|
41535
|
+
if (!agencyName && !sourceUrl && !branchLocation && !targetMode) return "";
|
|
41536
|
+
const previewArgs = [
|
|
41537
|
+
"ops reporting agency-setup-preview",
|
|
41538
|
+
agencyName ? `--agency-name ${quoteArg(agencyName)}` : "--agency-name <agency-name>",
|
|
41539
|
+
sourceUrl ? `--source-url ${quoteArg(sourceUrl)}` : "--source-url <official-source-url>",
|
|
41540
|
+
branchLocation ? `--branch-location ${quoteArg(branchLocation)}` : "--branch-location <branch-location>",
|
|
41541
|
+
targetMode ? `--target-mode ${quoteArg(targetMode)}` : "--target-mode founder_assisted",
|
|
41542
|
+
"--json"
|
|
41543
|
+
].join(" ");
|
|
41544
|
+
return [
|
|
41545
|
+
"",
|
|
41546
|
+
"Arbitrary-agency setup context:",
|
|
41547
|
+
...agencyName ? [`- Agency name: ${agencyName}`] : [],
|
|
41548
|
+
...sourceUrl ? [`- Official source URL: ${sourceUrl}`] : [],
|
|
41549
|
+
...branchLocation ? [`- Branch/location: ${branchLocation}`] : [],
|
|
41550
|
+
...targetMode ? [`- Target mode: ${targetMode}`] : [],
|
|
41551
|
+
`- Start with: npx --yes @f-o-h/cli@latest ${previewArgs}`,
|
|
41552
|
+
"- Then run launch-packet, launch-packet-skeletons, and launch-packet-evidence-check using public CLI commands only.",
|
|
41553
|
+
"- Treat missing customer credentials or approvals as expected holds only if the CLI gives machine-readable reason codes and next actions."
|
|
41554
|
+
].join("\n");
|
|
41555
|
+
}
|
|
41254
41556
|
function writePrompt(runDir, promptVersion, context = {}) {
|
|
41255
41557
|
const prompt = [
|
|
41256
41558
|
PROMPTS[promptVersion] ?? PROMPTS[DEFAULT_PROMPT_VERSION],
|
|
41257
41559
|
replayPromptContext(context.replayFile),
|
|
41258
|
-
knowledgeMissPromptContext(context.knowledgeQuestion, context.expectedAnswer)
|
|
41560
|
+
knowledgeMissPromptContext(context.knowledgeQuestion, context.expectedAnswer),
|
|
41561
|
+
agencySetupPromptContext(context)
|
|
41259
41562
|
].join("");
|
|
41260
41563
|
const path2 = (0, import_path19.join)(runDir, "prompt.txt");
|
|
41261
41564
|
(0, import_fs20.writeFileSync)(path2, `${prompt}
|
|
@@ -41327,7 +41630,11 @@ function buildRunArtifact(input) {
|
|
|
41327
41630
|
context: {
|
|
41328
41631
|
replay_file: input.session.replay_file ?? null,
|
|
41329
41632
|
knowledge_question: input.session.knowledge_question ?? null,
|
|
41330
|
-
expected_answer: input.session.expected_answer ?? null
|
|
41633
|
+
expected_answer: input.session.expected_answer ?? null,
|
|
41634
|
+
agency_name: input.session.agency_name ?? null,
|
|
41635
|
+
source_url: input.session.source_url ?? null,
|
|
41636
|
+
branch_location: input.session.branch_location ?? null,
|
|
41637
|
+
target_mode: input.session.target_mode ?? null
|
|
41331
41638
|
},
|
|
41332
41639
|
artifacts: {
|
|
41333
41640
|
terminal_transcript: null,
|
|
@@ -41349,19 +41656,31 @@ function buildRunArtifact(input) {
|
|
|
41349
41656
|
function registerEval(program3) {
|
|
41350
41657
|
const evalCommand = program3.command("eval").description("Run or summarize external-agent evaluation workflows");
|
|
41351
41658
|
const external = evalCommand.command("external-agent").description("Capture clean external coding-agent setup attempts");
|
|
41352
|
-
external.command("batch").description("Create a deterministic multi-model external-agent batch plan").option("--models <list>", "Comma-separated provider/model list", DEFAULT_BATCH_MODELS).option("--prompt-version <version>", "Prompt version", DEFAULT_PROMPT_VERSION).option("--replay-file <path>", "Local transcript/replay artifact to seed replay-failure prompts").option("--knowledge-question <text>", "Question to seed knowledge-miss prompts").option("--expected-answer <text>", "Expected answer or missing fact for planted knowledge-miss prompts").option("--workspace-type <type>", "Workspace type label", "clean-no-repo").option("--agent-shell <name>", "Agent shell label", "vscode-terminal").option("--out-dir <path>", "Batch output directory").option("--json", "Output as JSON").action(async (opts) => {
|
|
41659
|
+
external.command("batch").description("Create a deterministic multi-model external-agent batch plan").option("--models <list>", "Comma-separated provider/model list", DEFAULT_BATCH_MODELS).option("--prompt-version <version>", "Prompt version", DEFAULT_PROMPT_VERSION).option("--replay-file <path>", "Local transcript/replay artifact to seed replay-failure prompts").option("--knowledge-question <text>", "Question to seed knowledge-miss prompts").option("--expected-answer <text>", "Expected answer or missing fact for planted knowledge-miss prompts").option("--agency-name <name>", "Agency name to seed arbitrary-agency setup prompts").option("--source-url <url>", "Official source URL to seed arbitrary-agency setup prompts").option("--branch-location <value>", "Branch/location to seed arbitrary-agency setup prompts").option("--target-mode <mode>", "Target launch/exposure mode for arbitrary-agency setup prompts").option("--workspace-type <type>", "Workspace type label", "clean-no-repo").option("--agent-shell <name>", "Agent shell label", "vscode-terminal").option("--out-dir <path>", "Batch output directory").option("--json", "Output as JSON").action(async (opts) => {
|
|
41353
41660
|
const promptVersion = String(opts.promptVersion || DEFAULT_PROMPT_VERSION);
|
|
41354
41661
|
const batchDir = (0, import_path19.resolve)(String(opts.outDir || defaultBatchDir(promptVersion)));
|
|
41355
41662
|
const replayFile = opts.replayFile ? (0, import_path19.resolve)(String(opts.replayFile)) : void 0;
|
|
41356
41663
|
const knowledgeQuestion = opts.knowledgeQuestion ? String(opts.knowledgeQuestion) : void 0;
|
|
41357
41664
|
const expectedAnswer = opts.expectedAnswer ? String(opts.expectedAnswer) : void 0;
|
|
41665
|
+
const agencyName = opts.agencyName ? String(opts.agencyName) : void 0;
|
|
41666
|
+
const sourceUrl = opts.sourceUrl ? String(opts.sourceUrl) : void 0;
|
|
41667
|
+
const branchLocation = opts.branchLocation ? String(opts.branchLocation) : void 0;
|
|
41668
|
+
const targetMode = opts.targetMode ? String(opts.targetMode) : void 0;
|
|
41358
41669
|
const models = parseModelList(String(opts.models || DEFAULT_BATCH_MODELS));
|
|
41359
41670
|
(0, import_fs20.mkdirSync)(batchDir, { recursive: true });
|
|
41360
41671
|
const runs2 = models.map((model, index) => {
|
|
41361
41672
|
const runId = `${String(index + 1).padStart(2, "0")}-${safeSlug(model.provider)}-${safeSlug(model.name)}`;
|
|
41362
41673
|
const runDir = (0, import_path19.join)(batchDir, runId);
|
|
41363
41674
|
(0, import_fs20.mkdirSync)(runDir, { recursive: true });
|
|
41364
|
-
const promptPath = writePrompt(runDir, promptVersion, {
|
|
41675
|
+
const promptPath = writePrompt(runDir, promptVersion, {
|
|
41676
|
+
replayFile,
|
|
41677
|
+
knowledgeQuestion,
|
|
41678
|
+
expectedAnswer,
|
|
41679
|
+
agencyName,
|
|
41680
|
+
sourceUrl,
|
|
41681
|
+
branchLocation,
|
|
41682
|
+
targetMode
|
|
41683
|
+
});
|
|
41365
41684
|
const commandArgs = [
|
|
41366
41685
|
"eval",
|
|
41367
41686
|
"external-agent",
|
|
@@ -41382,6 +41701,10 @@ function registerEval(program3) {
|
|
|
41382
41701
|
if (replayFile) commandArgs.push("--replay-file", replayFile);
|
|
41383
41702
|
if (knowledgeQuestion) commandArgs.push("--knowledge-question", knowledgeQuestion);
|
|
41384
41703
|
if (expectedAnswer) commandArgs.push("--expected-answer", expectedAnswer);
|
|
41704
|
+
if (agencyName) commandArgs.push("--agency-name", agencyName);
|
|
41705
|
+
if (sourceUrl) commandArgs.push("--source-url", sourceUrl);
|
|
41706
|
+
if (branchLocation) commandArgs.push("--branch-location", branchLocation);
|
|
41707
|
+
if (targetMode) commandArgs.push("--target-mode", targetMode);
|
|
41385
41708
|
return {
|
|
41386
41709
|
run_id: runId,
|
|
41387
41710
|
model_provider: model.provider,
|
|
@@ -41401,6 +41724,10 @@ function registerEval(program3) {
|
|
|
41401
41724
|
replay_file: replayFile ?? null,
|
|
41402
41725
|
knowledge_question: knowledgeQuestion ?? null,
|
|
41403
41726
|
expected_answer: expectedAnswer ?? null,
|
|
41727
|
+
agency_name: agencyName ?? null,
|
|
41728
|
+
source_url: sourceUrl ?? null,
|
|
41729
|
+
branch_location: branchLocation ?? null,
|
|
41730
|
+
target_mode: targetMode ?? null,
|
|
41404
41731
|
workspace_type: String(opts.workspaceType || "clean-no-repo"),
|
|
41405
41732
|
agent_shell: String(opts.agentShell || "vscode-terminal"),
|
|
41406
41733
|
run_count: runs2.length,
|
|
@@ -41425,16 +41752,28 @@ function registerEval(program3) {
|
|
|
41425
41752
|
extra: { batch }
|
|
41426
41753
|
}), { json: Boolean(opts.json) });
|
|
41427
41754
|
});
|
|
41428
|
-
external.command("run").description("Launch an instrumented shell and emit external_agent_run.v1 when it exits").option("--model-provider <name>", "Model provider label", "unknown").option("--model-name <name>", "Model name label", "unknown-model").option("--prompt-version <version>", "Prompt version", DEFAULT_PROMPT_VERSION).option("--replay-file <path>", "Local transcript/replay artifact to seed replay-failure prompts").option("--knowledge-question <text>", "Question to seed knowledge-miss prompts").option("--expected-answer <text>", "Expected answer or missing fact for planted knowledge-miss prompts").option("--workspace-type <type>", "Workspace type label", "clean-no-repo").option("--agent-shell <name>", "Agent shell label", "vscode-terminal").option("--out-dir <path>", "Run output directory").option("--status <status>", "Final status when not interactively classified: pass|hold|fail", "hold").option("--reason-code <code>", "Failure/hold reason code", "external_agent_run_needs_review").option("--shell <command>", "Shell command to launch for capture").option("--no-shell", "Do not launch a shell; create/finalize artifacts immediately").option("--json", "Output as JSON").action(async (opts) => {
|
|
41755
|
+
external.command("run").description("Launch an instrumented shell and emit external_agent_run.v1 when it exits").option("--model-provider <name>", "Model provider label", "unknown").option("--model-name <name>", "Model name label", "unknown-model").option("--prompt-version <version>", "Prompt version", DEFAULT_PROMPT_VERSION).option("--replay-file <path>", "Local transcript/replay artifact to seed replay-failure prompts").option("--knowledge-question <text>", "Question to seed knowledge-miss prompts").option("--expected-answer <text>", "Expected answer or missing fact for planted knowledge-miss prompts").option("--agency-name <name>", "Agency name to seed arbitrary-agency setup prompts").option("--source-url <url>", "Official source URL to seed arbitrary-agency setup prompts").option("--branch-location <value>", "Branch/location to seed arbitrary-agency setup prompts").option("--target-mode <mode>", "Target launch/exposure mode for arbitrary-agency setup prompts").option("--workspace-type <type>", "Workspace type label", "clean-no-repo").option("--agent-shell <name>", "Agent shell label", "vscode-terminal").option("--out-dir <path>", "Run output directory").option("--status <status>", "Final status when not interactively classified: pass|hold|fail", "hold").option("--reason-code <code>", "Failure/hold reason code", "external_agent_run_needs_review").option("--shell <command>", "Shell command to launch for capture").option("--no-shell", "Do not launch a shell; create/finalize artifacts immediately").option("--json", "Output as JSON").action(async (opts) => {
|
|
41429
41756
|
const status = normalizeStatus(opts.status);
|
|
41430
41757
|
const promptVersion = String(opts.promptVersion || DEFAULT_PROMPT_VERSION);
|
|
41431
41758
|
const runDir = (0, import_path19.resolve)(String(opts.outDir || defaultRunDir(opts.modelName, promptVersion)));
|
|
41432
41759
|
const replayFile = opts.replayFile ? (0, import_path19.resolve)(String(opts.replayFile)) : void 0;
|
|
41433
41760
|
const knowledgeQuestion = opts.knowledgeQuestion ? String(opts.knowledgeQuestion) : void 0;
|
|
41434
41761
|
const expectedAnswer = opts.expectedAnswer ? String(opts.expectedAnswer) : void 0;
|
|
41762
|
+
const agencyName = opts.agencyName ? String(opts.agencyName) : void 0;
|
|
41763
|
+
const sourceUrl = opts.sourceUrl ? String(opts.sourceUrl) : void 0;
|
|
41764
|
+
const branchLocation = opts.branchLocation ? String(opts.branchLocation) : void 0;
|
|
41765
|
+
const targetMode = opts.targetMode ? String(opts.targetMode) : void 0;
|
|
41435
41766
|
(0, import_fs20.mkdirSync)(runDir, { recursive: true });
|
|
41436
41767
|
const runId = runDir.split(/[\\/]/).filter(Boolean).slice(-1)[0];
|
|
41437
|
-
const promptPath = writePrompt(runDir, promptVersion, {
|
|
41768
|
+
const promptPath = writePrompt(runDir, promptVersion, {
|
|
41769
|
+
replayFile,
|
|
41770
|
+
knowledgeQuestion,
|
|
41771
|
+
expectedAnswer,
|
|
41772
|
+
agencyName,
|
|
41773
|
+
sourceUrl,
|
|
41774
|
+
branchLocation,
|
|
41775
|
+
targetMode
|
|
41776
|
+
});
|
|
41438
41777
|
const shell = inferShell(opts.shell);
|
|
41439
41778
|
const session = {
|
|
41440
41779
|
schema_version: "external_agent_capture_session.v1",
|
|
@@ -41446,6 +41785,10 @@ function registerEval(program3) {
|
|
|
41446
41785
|
replay_file: replayFile ?? null,
|
|
41447
41786
|
knowledge_question: knowledgeQuestion ?? null,
|
|
41448
41787
|
expected_answer: expectedAnswer ?? null,
|
|
41788
|
+
agency_name: agencyName ?? null,
|
|
41789
|
+
source_url: sourceUrl ?? null,
|
|
41790
|
+
branch_location: branchLocation ?? null,
|
|
41791
|
+
target_mode: targetMode ?? null,
|
|
41449
41792
|
workspace_type: String(opts.workspaceType || "clean-no-repo"),
|
|
41450
41793
|
agent_shell: String(opts.agentShell || shell.label),
|
|
41451
41794
|
manual_intervention_count: 0,
|
|
@@ -41728,10 +42071,8 @@ var CLI_MISSION_EXAMPLES = [
|
|
|
41728
42071
|
{ mission: "Start", command: "foh start", description: "guided setup and next action selector" },
|
|
41729
42072
|
{ mission: "Setup", command: "foh setup --phone-mode observe --json", description: "create or update agent, widget, voice config, and proof scaffold" },
|
|
41730
42073
|
{ mission: "Prove", command: "foh prove --agent <agent_id> --mission widget --json", description: "produce a machine-readable proof report" },
|
|
41731
|
-
{ mission: "
|
|
41732
|
-
{ mission: "Debug", command: "foh debug --out test-results/foh-cli-diag.latest.json --json", description: "collect auth/org/API diagnostics" }
|
|
41733
|
-
{ mission: "Improve", command: "foh bug improve --from-file <artifact.json> --json", description: "convert a failure artifact into a redacted improvement packet" },
|
|
41734
|
-
{ mission: "Publish", command: "foh agent publish --agent <agent_id> --json", description: "publish after proof gates pass" }
|
|
42074
|
+
{ mission: "Publish", command: "foh publish --agent <agent_id> --json", description: "publish when proof and release evidence pass" },
|
|
42075
|
+
{ mission: "Debug", command: "foh debug --out test-results/foh-cli-diag.latest.json --json", description: "collect auth/org/API diagnostics" }
|
|
41735
42076
|
];
|
|
41736
42077
|
function missionHelpText() {
|
|
41737
42078
|
return [
|
|
@@ -41739,7 +42080,7 @@ function missionHelpText() {
|
|
|
41739
42080
|
"Common missions:",
|
|
41740
42081
|
...CLI_MISSION_EXAMPLES.map((item) => ` ${item.command.padEnd(66)} ${item.description}`),
|
|
41741
42082
|
"",
|
|
41742
|
-
"For AI agents: prefer --json
|
|
42083
|
+
"For AI agents: prefer --json, follow next_commands exactly, and treat certify/eval/bug as advanced operator surfaces."
|
|
41743
42084
|
].join("\n");
|
|
41744
42085
|
}
|
|
41745
42086
|
function addMissionHelp(program3) {
|
|
@@ -41832,6 +42173,7 @@ registerCertify(program2);
|
|
|
41832
42173
|
registerDiag(program2);
|
|
41833
42174
|
registerBug(program2);
|
|
41834
42175
|
registerProve(program2);
|
|
42176
|
+
registerAgentPublishCommand(program2, { publicAlias: true });
|
|
41835
42177
|
registerEval(program2);
|
|
41836
42178
|
registerUpdate(program2);
|
|
41837
42179
|
registerHome(program2);
|