@salesforce/afv-skills 1.59.0 → 1.61.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/package.json +1 -1
- package/skills/agentforce-architecture-analyze/SKILL.md +66 -17
- package/skills/agentforce-architecture-analyze/assets/cli/show_access_token.yaml +4 -7
- package/skills/agentforce-architecture-analyze/references/contract.json +1 -1
- package/skills/agentforce-architecture-analyze/scripts/emit_env.py +2 -2
- package/skills/agentforce-architecture-analyze/scripts/main.py +40 -44
- package/skills/agentforce-architecture-analyze/scripts/rest_client.py +11 -3
- package/skills/agentforce-architecture-analyze/scripts/sf_cli.py +77 -10
- package/skills/agentforce-architecture-analyze/scripts/tests/test_end_to_end_fixture.py +1 -0
- package/skills/agentforce-architecture-analyze/scripts/tests/test_flow_children_inflation.py +1 -0
- package/skills/agentforce-architecture-analyze/scripts/tests/test_main_pipeline.py +53 -2
- package/skills/agentforce-architecture-analyze/scripts/tests/test_resolve_creds.py +184 -36
- package/skills/agentforce-architecture-analyze/scripts/tests/test_rest_client.py +17 -0
- package/skills/agentforce-architecture-analyze/scripts/tests/test_sf_cli.py +165 -11
- package/skills/agentforce-architecture-analyze/scripts/tests/test_skill_md_pipeline_block.py +319 -0
- package/skills/agentforce-d360-analyze/SKILL.md +28 -10
- package/skills/agentforce-d360-analyze/scripts/dc.py +200 -50
- package/skills/agentforce-d360-analyze/scripts/discover_sessions.py +10 -6
- package/skills/agentforce-d360-analyze/scripts/fetch_dc.py +22 -6
- package/skills/agentforce-d360-analyze/scripts/resolve_session.py +21 -13
- package/skills/agentforce-d360-analyze/scripts/tests/test_dc_and_resolve_session.py +298 -76
- package/skills/agentforce-d360-analyze/scripts/tests/test_default_target_org.py +432 -0
- package/skills/agentforce-d360-analyze/scripts/tests/test_discover_sessions.py +1 -1
- package/skills/agentforce-d360-analyze/scripts/tests/test_resolve_session_main.py +9 -3
- package/skills/agentforce-d360-analyze/scripts/tests/test_skill_md_prefix_block.py +176 -0
- package/skills/consumer-goods-accruals-datakit-deploy/SKILL.md +17 -27
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/setup.js +7 -17
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/00-check-prerequisites.js +47 -63
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/01-download-static-resource.js +10 -13
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/02-replace-org-id.js +46 -46
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/03-deploy-metadata.js +4 -21
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/06-create-dataspace.js +58 -82
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/07-deploy-accruals-reports.js +16 -315
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/08-deploy-ui.js +9 -24
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/09-completion.js +44 -44
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/utils.js +11 -63
- package/skills/consumer-goods-rtr-datacloud-export-configure/SKILL.md +2 -1
- package/skills/consumer-goods-tpe-dashboard-configure/SKILL.md +2 -1
- package/skills/consumer-goods-tpe-dashboard-custom-kpi-configure/SKILL.md +2 -1
- package/skills/consumer-goods-tpe-datakit-deploy/SKILL.md +2 -1
- package/skills/data360-schema-get/SKILL.md +3 -3
- package/skills/design-systems-slds-validate/references/report-format.md +1 -1
- package/skills/dx-org-manage/SKILL.md +1 -0
- package/skills/dx-org-shape-manage/SKILL.md +1 -0
- package/skills/dx-org-snapshot-manage/SKILL.md +172 -0
- package/skills/dx-org-snapshot-manage/examples/create_error_output.json +16 -0
- package/skills/dx-org-snapshot-manage/examples/create_success_output.json +19 -0
- package/skills/dx-org-snapshot-manage/examples/delete_output.json +9 -0
- package/skills/dx-org-snapshot-manage/examples/get_output.json +19 -0
- package/skills/dx-org-snapshot-manage/examples/list_output.json +36 -0
- package/skills/dx-org-snapshot-manage/references/cli_flags.md +179 -0
- package/skills/dx-org-snapshot-manage/references/snapshot_usage.md +55 -0
- package/skills/dx-org-trial-expiration-check/SKILL.md +1 -1
- package/skills/dx-org-trial-expiration-check/scripts/check_expiration.sh +2 -2
- package/skills/education-cloud-student-recruitment-agent-configure/SKILL.md +7 -5
- package/skills/education-cloud-student-recruitment-agent-configure/references/prerequisites.md +11 -11
- package/skills/experience-content-media-image-generate/SKILL.md +83 -0
- package/skills/experience-content-media-image-generate/scripts/download-image.sh +84 -0
- package/skills/external-diagram-mermaid-generate/SKILL.md +12 -12
- package/skills/field-service-data-capture-migrate/references/component-mapping.md +1 -1
- package/skills/field-service-data-capture-migrate/references/fsm-dc-capability-catalog.md +1 -2
- package/skills/field-service-data-capture-migrate/references/known-deploy-errors.md +1 -0
- package/skills/field-service-data-capture-migrate/references/transformer-rules.md +1 -1
- package/skills/field-service-data-capture-migrate/scripts/transform_flow.py +12 -1
- package/skills/field-service-data-capture-migrate/scripts/vendor/build_flow.py +4 -1
- package/skills/field-service-setup-orchestrator-get/SKILL.md +0 -1
- package/skills/insurance-brokerage-agency-billing-configure/SKILL.md +233 -0
- package/skills/insurance-brokerage-agency-billing-configure/references/accounting-setup.md +117 -0
- package/skills/insurance-brokerage-agency-billing-configure/references/billing-rules-config.md +237 -0
- package/skills/insurance-brokerage-agency-billing-configure/references/billing-settings.md +271 -0
- package/skills/insurance-brokerage-agency-billing-configure/references/demo-policy-config.md +138 -0
- package/skills/insurance-brokerage-agency-billing-configure/references/org-defaults.md +64 -0
- package/skills/insurance-brokerage-agency-billing-configure/references/permissions-config.md +226 -0
- package/skills/insurance-brokerage-agency-billing-configure/references/prerequisites.md +142 -0
- package/skills/life-sciences-fieldsalesrep-coordinate/SKILL.md +3 -2
- package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-5-visit-creation-execution-state-and-recovery.md +3 -3
- package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-5-visit-creation-overview.md +68 -45
- package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-5-visit-creation-visit-creation-data.md +17 -18
- package/skills/life-sciences-kam-coordinate/references/stage-5-data-and-plan-templates-overview.md +16 -3
- package/skills/life-sciences-kam-coordinate/references/stage-5-data-creation-data.md +16 -13
- package/skills/marketing-message-test/SKILL.md +194 -0
- package/skills/marketing-message-test/references/api-contract.md +333 -0
- package/skills/omnistudio-callable-apex-generate/SKILL.md +3 -3
- package/skills/omnistudio-datamapper-generate/SKILL.md +6 -6
- package/skills/omnistudio-datapacks-deploy/SKILL.md +11 -11
- package/skills/omnistudio-dependencies-analyze/SKILL.md +5 -5
- package/skills/omnistudio-epc-catalog-generate/SKILL.md +6 -6
- package/skills/omnistudio-flexcard-generate/SKILL.md +6 -6
- package/skills/omnistudio-integration-procedure-generate/SKILL.md +6 -6
- package/skills/omnistudio-omniscript-generate/SKILL.md +6 -5
- package/skills/platform-apex-logs-debug/SKILL.md +1 -0
- package/skills/platform-metadata-deploy/SKILL.md +1 -0
- package/skills/platform-models-api-configure/SKILL.md +5 -5
- package/skills/platform-soql-query/SKILL.md +1 -0
- package/skills/service-itsm-agentic-setup-cmdb-coordinate/SKILL.md +17 -6
- package/skills/service-itsm-agentic-setup-incident-sla-configure/SKILL.md +107 -192
- package/skills/service-itsm-agentic-setup-incident-sla-configure/assets/attach-milestone-action.json +6 -6
- package/skills/service-itsm-agentic-setup-incident-sla-configure/examples/milestone-patterns.md +49 -20
- package/skills/service-itsm-agentic-setup-incident-sla-configure/examples/output-templates.md +4 -4
- package/skills/service-itsm-agentic-setup-incident-sla-configure/references/mcp-invocation.md +224 -290
- package/skills/service-itsm-agentic-setup-incident-sla-configure/references/workflow.md +295 -0
- package/skills/service-itsm-incident-priority-configure/SKILL.md +1 -1
- package/skills/service-itsm-slack-itservice-configure/SKILL.md +2 -1
- package/skills/service-itsm-slack-itservice-configure/references/manage-slack-connection.md +2 -2
- package/skills/service-omni-channel-setup-coordinate/SKILL.md +20 -13
- package/skills/service-omni-channel-setup-coordinate/scripts/integration-driver.sh +5 -55
- package/skills/service-omni-channel-setup-coordinate/scripts/tests/test_omni_contracts.py +0 -38
- package/skills/service-omni-command-center-analyze/SKILL.md +2 -3
- package/skills/service-omni-command-center-analyze/scripts/analyze.sh +3 -3
- package/skills/tableau-next-asset-create/README.md +65 -0
- package/skills/tableau-next-asset-create/SKILL.md +409 -0
- package/skills/tableau-next-asset-create/references/admin-users.md +149 -0
- package/skills/tableau-next-asset-create/references/ai-readiness.md +355 -0
- package/skills/tableau-next-asset-create/references/alerts.md +111 -0
- package/skills/tableau-next-asset-create/references/build-workflow.md +819 -0
- package/skills/tableau-next-asset-create/references/dashboard-authoring.md +302 -0
- package/skills/tableau-next-asset-create/references/dashboard-design-principles.md +352 -0
- package/skills/tableau-next-asset-create/references/data-transform-gotchas.md +210 -0
- package/skills/tableau-next-asset-create/references/data-understanding.md +387 -0
- package/skills/tableau-next-asset-create/references/deep-reference-index.md +74 -0
- package/skills/tableau-next-asset-create/references/destructive-operations.md +62 -0
- package/skills/tableau-next-asset-create/references/edit-dashboard.md +273 -0
- package/skills/tableau-next-asset-create/references/edit-visualization.md +529 -0
- package/skills/tableau-next-asset-create/references/empty-source-handling.md +104 -0
- package/skills/tableau-next-asset-create/references/ingest-and-metric-gotchas.md +638 -0
- package/skills/tableau-next-asset-create/references/insight-bundle.md +69 -0
- package/skills/tableau-next-asset-create/references/large-flat-file-handling.md +331 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/_envelope.json +54 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/_shared-widget-fields.json +122 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/add_page.json +29 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/delete_page.json +27 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/discard_dashboard.json +11 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/move_widget.json +30 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/move_widget_to_page.json +30 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/place_widget_on_page.json +30 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/remove_widget_from_dashboard.json +16 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/remove_widget_from_page.json +26 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/rename_page.json +28 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/save_dashboard.json +18 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/undo.json +11 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/upsert_button_widget.json +69 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/upsert_container_widget.json +88 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/upsert_filter_widget.json +146 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/upsert_metric_widget.json +78 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/upsert_navigation_widget.json +80 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/upsert_parameter_widget.json +160 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/upsert_text_widget.json +103 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/upsert_visualization_widget.json +68 -0
- package/skills/tableau-next-asset-create/references/sdm-tool-reference.md +721 -0
- package/skills/tableau-next-asset-create/references/semantic-query-and-enrichment.md +355 -0
- package/skills/tableau-next-asset-create/references/shared-gates.md +322 -0
- package/skills/tableau-next-asset-create/references/sharing-and-promotion.md +306 -0
- package/skills/tableau-next-asset-create/references/tasks/ai-readiness-audit.md +51 -0
- package/skills/tableau-next-asset-create/references/tasks/analyze-data.md +48 -0
- package/skills/tableau-next-asset-create/references/tasks/build-dashboard.md +66 -0
- package/skills/tableau-next-asset-create/references/tasks/build-end-to-end.md +73 -0
- package/skills/tableau-next-asset-create/references/tasks/create-data-transform.md +51 -0
- package/skills/tableau-next-asset-create/references/tasks/create-viz.md +58 -0
- package/skills/tableau-next-asset-create/references/tasks/edit-dashboard.md +80 -0
- package/skills/tableau-next-asset-create/references/tasks/edit-sdm.md +106 -0
- package/skills/tableau-next-asset-create/references/tasks/edit-viz.md +40 -0
- package/skills/tableau-next-asset-create/references/tasks/enrich-model.md +68 -0
- package/skills/tableau-next-asset-create/references/tasks/ingest-flat-file.md +68 -0
- package/skills/tableau-next-asset-create/references/tasks/manage-alert.md +35 -0
- package/skills/tableau-next-asset-create/references/tasks/profile-dataset.md +47 -0
- package/skills/tableau-next-asset-create/references/tasks/promote-or-reuse.md +46 -0
- package/skills/tableau-next-asset-create/references/tasks/provision-user.md +39 -0
- package/skills/tableau-next-asset-create/references/tasks/query-model.md +92 -0
- package/skills/tableau-next-asset-create/references/tasks/review-verified-questions.md +42 -0
- package/skills/tableau-next-asset-create/references/tasks/share-asset.md +37 -0
- package/skills/tableau-next-asset-create/references/verified-questions.md +125 -0
- package/skills/tableau-next-asset-create/references/viz-authoring.md +992 -0
- package/skills/service-de-channel-consent-configure/SKILL.md +0 -230
- package/skills/service-itsm-agentic-setup-incident-sla-configure/assets/predefined-incident-policy.json +0 -102
|
@@ -8,17 +8,22 @@ Two responsibilities:
|
|
|
8
8
|
column names — those live in the .sql files.
|
|
9
9
|
|
|
10
10
|
2. **Transport.** `resolve_org(alias)` shells out to `sf org display`
|
|
11
|
-
for the instance URL
|
|
11
|
+
for the instance URL and `sf org auth show-access-token` for the
|
|
12
|
+
access token. `post(sql, instance_url, token)`
|
|
12
13
|
POSTs the SQL to the Data Cloud Query API and returns parsed rows.
|
|
13
14
|
Errors route through `DCQueryError` with the full response body + SQL
|
|
14
15
|
context so callers can surface a useful message.
|
|
16
|
+
`default_target_org()` reads the sf CLI default target org for entry
|
|
17
|
+
points invoked without `--org`. Both it and `resolve_org` run the
|
|
18
|
+
`show-access-token` capability preflight as their first sf call, so on
|
|
19
|
+
either path a too-old CLI fails with the upgrade message first.
|
|
15
20
|
|
|
16
21
|
Persistence lives in `storage.save`.
|
|
17
22
|
"""
|
|
18
23
|
from __future__ import annotations
|
|
19
24
|
|
|
20
25
|
import json
|
|
21
|
-
import
|
|
26
|
+
import re
|
|
22
27
|
import subprocess
|
|
23
28
|
import sys
|
|
24
29
|
import urllib.error
|
|
@@ -71,51 +76,206 @@ wording has shifted across sf CLI builds while the subcommand has been
|
|
|
71
76
|
stable since forcedotcom/cli#3560 landed."""
|
|
72
77
|
|
|
73
78
|
|
|
74
|
-
|
|
79
|
+
# Token-redaction patterns, vendored from agentforce-architecture-analyze's
|
|
80
|
+
# rest_client (this skill is self-contained and must not import across
|
|
81
|
+
# skills). sf CLI failure output can echo the access token — e.g. a
|
|
82
|
+
# `show-access-token --json` run that exits non-zero with the payload on
|
|
83
|
+
# stdout — so every stderr/stdout string is scrubbed before it reaches a
|
|
84
|
+
# SystemExit message. Deliberately permissive: over-redact, never leak.
|
|
85
|
+
_AUTH_HEADER_RE = re.compile(r"(Authorization\s*:\s*Bearer\s+)\S+", re.IGNORECASE) # @rule-suppress starter-sec-002 — re.compile, not exec/eval
|
|
86
|
+
_BEARER_RE = re.compile(r"(\bBearer\s+)[^\s\"']+", re.IGNORECASE) # @rule-suppress starter-sec-002 — re.compile, not exec/eval
|
|
87
|
+
_ACCESS_TOKEN_QS_RE = re.compile(r"(access[_]?token\s*=\s*)[^&\s\"']+", re.IGNORECASE) # @rule-suppress starter-sec-002 — re.compile, not exec/eval
|
|
88
|
+
_ACCESS_TOKEN_JSON_RE = re.compile(r"(\"access[_]?token\"\s*:\s*\")[^\"]*", re.IGNORECASE) # @rule-suppress starter-sec-002 — re.compile, not exec/eval
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def _redact_text(text: str | None) -> str:
|
|
92
|
+
"""Scrub bearer tokens and accessToken values from sf CLI output."""
|
|
93
|
+
if not text:
|
|
94
|
+
return ""
|
|
95
|
+
text = _AUTH_HEADER_RE.sub(r"\1<redacted>", text)
|
|
96
|
+
text = _BEARER_RE.sub(r"\1<redacted>", text)
|
|
97
|
+
text = _ACCESS_TOKEN_QS_RE.sub(r"\1<redacted>", text)
|
|
98
|
+
text = _ACCESS_TOKEN_JSON_RE.sub(r"\1<redacted>", text)
|
|
99
|
+
return text
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def _run_sf_json(argv: list[str]) -> dict:
|
|
75
103
|
"""Shell out + parse JSON. SystemExits on FileNotFoundError /
|
|
76
|
-
CalledProcessError so callers get a clean message instead of a stack.
|
|
104
|
+
CalledProcessError so callers get a clean message instead of a stack.
|
|
105
|
+
Failure output is redacted before it is surfaced."""
|
|
77
106
|
try:
|
|
78
|
-
r = subprocess.run(
|
|
79
|
-
argv, capture_output=True, text=True, check=True, env=env,
|
|
80
|
-
)
|
|
107
|
+
r = subprocess.run(argv, capture_output=True, text=True, check=True)
|
|
81
108
|
except FileNotFoundError:
|
|
82
109
|
raise SystemExit("sf CLI not found on PATH — install Salesforce CLI first")
|
|
83
110
|
except subprocess.CalledProcessError as e:
|
|
111
|
+
detail = _redact_text((e.stderr or "").strip() or (e.stdout or "").strip())
|
|
112
|
+
raise SystemExit(f"{' '.join(argv[:4])}... failed:\n{detail}") from None
|
|
113
|
+
return json.loads(r.stdout)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
_show_access_token_capability_ok = False
|
|
117
|
+
"""Set once the preflight succeeds; the check then never reruns in this
|
|
118
|
+
process. Failures are NOT cached, so a fixed PATH/upgrade is picked up on
|
|
119
|
+
the next call."""
|
|
120
|
+
|
|
121
|
+
_SHOW_ACCESS_TOKEN_HELP_SIGNATURE_RE = re.compile(
|
|
122
|
+
r"\$\s*sf\s+org\s+auth\s+show-access-token\b"
|
|
123
|
+
)
|
|
124
|
+
"""USAGE-line form that real `--help` output always contains
|
|
125
|
+
(`$ sf org auth show-access-token -o <value> ...`). The bare command name is
|
|
126
|
+
not enough: unknown-command notices echo it too
|
|
127
|
+
(`Command org:auth:show-access-token not found`,
|
|
128
|
+
`show-access-token is not a sf command`). A zero-exit probe whose output
|
|
129
|
+
lacks the USAGE form is treated as a failed check."""
|
|
130
|
+
|
|
131
|
+
_ANSI_ESCAPE_RE = re.compile(r"\x1b\[[0-9;?]*[ -/]*[@-~]")
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def _assert_show_access_token_capability() -> None:
|
|
135
|
+
"""Fail fast if the installed sf CLI lacks `sf org auth show-access-token`.
|
|
136
|
+
|
|
137
|
+
That command is the only supported token-retrieval path
|
|
138
|
+
(forcedotcom/cli#3560). Probing `--help` needs no org auth and turns a
|
|
139
|
+
confusing downstream failure into an actionable upgrade message.
|
|
140
|
+
`default_target_org` and `resolve_org` each call this first, ahead of
|
|
141
|
+
every other sf call they make. A successful probe is cached for the
|
|
142
|
+
process lifetime, so the second call costs nothing.
|
|
143
|
+
|
|
144
|
+
Exit status alone is not trusted: a CLI build that answers an unknown
|
|
145
|
+
command with exit 0 (e.g. printing top-level help or a "not found"
|
|
146
|
+
notice) would otherwise pass. The probe therefore also requires the
|
|
147
|
+
command's USAGE line (`$ sf org auth show-access-token`) in the
|
|
148
|
+
ANSI-stripped stdout+stderr; if it is absent the check fails and is not
|
|
149
|
+
cached.
|
|
150
|
+
"""
|
|
151
|
+
global _show_access_token_capability_ok
|
|
152
|
+
if _show_access_token_capability_ok:
|
|
153
|
+
return
|
|
154
|
+
try:
|
|
155
|
+
proc = subprocess.run(
|
|
156
|
+
["sf", "org", "auth", "show-access-token", "--help"],
|
|
157
|
+
capture_output=True,
|
|
158
|
+
text=True,
|
|
159
|
+
timeout=30,
|
|
160
|
+
check=True,
|
|
161
|
+
)
|
|
162
|
+
except FileNotFoundError as exc:
|
|
84
163
|
raise SystemExit(
|
|
85
|
-
|
|
164
|
+
"sf CLI not found on PATH — install Salesforce CLI first"
|
|
165
|
+
) from exc
|
|
166
|
+
except subprocess.CalledProcessError as exc:
|
|
167
|
+
detail = (
|
|
168
|
+
_redact_text((exc.stderr or "").strip() or (exc.stdout or "").strip())
|
|
169
|
+
or "unknown error"
|
|
86
170
|
)
|
|
87
|
-
|
|
171
|
+
raise SystemExit(
|
|
172
|
+
"sf CLI is missing required command "
|
|
173
|
+
"'sf org auth show-access-token'. Upgrade/reinstall Salesforce CLI "
|
|
174
|
+
"to a build that provides this command, then retry.\n"
|
|
175
|
+
f"Preflight detail: {detail}"
|
|
176
|
+
) from exc
|
|
177
|
+
except subprocess.TimeoutExpired as exc:
|
|
178
|
+
raise SystemExit(
|
|
179
|
+
"sf CLI capability preflight for 'sf org auth show-access-token' "
|
|
180
|
+
"timed out after 30s"
|
|
181
|
+
) from exc
|
|
182
|
+
help_text = _ANSI_ESCAPE_RE.sub(
|
|
183
|
+
"", f"{proc.stdout or ''}\n{proc.stderr or ''}",
|
|
184
|
+
)
|
|
185
|
+
if not _SHOW_ACCESS_TOKEN_HELP_SIGNATURE_RE.search(help_text):
|
|
186
|
+
# Zero exit without the command's help signature — the CLI did not
|
|
187
|
+
# recognise the command. Fail (uncached) like a non-zero exit.
|
|
188
|
+
# Redact before truncating so a token can never be split past the regex.
|
|
189
|
+
detail = (
|
|
190
|
+
_redact_text(help_text.strip())[:500]
|
|
191
|
+
or "help output lacked the command signature"
|
|
192
|
+
)
|
|
193
|
+
raise SystemExit(
|
|
194
|
+
"sf CLI is missing required command "
|
|
195
|
+
"'sf org auth show-access-token'. Upgrade/reinstall Salesforce CLI "
|
|
196
|
+
"to a build that provides this command, then retry.\n"
|
|
197
|
+
f"Preflight detail: {detail}"
|
|
198
|
+
)
|
|
199
|
+
_show_access_token_capability_ok = True
|
|
88
200
|
|
|
89
201
|
|
|
90
|
-
|
|
91
|
-
"
|
|
202
|
+
NO_DEFAULT_ORG_MSG = (
|
|
203
|
+
"no --org given and no default target org set — run "
|
|
204
|
+
"`sf config set target-org <alias>` or pass --org <alias>"
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def default_target_org() -> str:
|
|
209
|
+
"""Return the sf CLI default target org alias/username.
|
|
92
210
|
|
|
93
|
-
|
|
211
|
+
Used by entry points when ``--org`` is omitted ("my org" means the CLI
|
|
212
|
+
default). Reads ``.result[0].value`` from
|
|
213
|
+
``sf config get target-org --json``. Raises SystemExit with a clear,
|
|
214
|
+
redacted message when the CLI is missing, fails, times out, returns
|
|
215
|
+
non-JSON, or has no default set.
|
|
94
216
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
217
|
+
The show-access-token capability preflight runs first, before
|
|
218
|
+
``sf config get``. A CLI too old to fetch a token then fails with the
|
|
219
|
+
upgrade/reinstall message, not a misleading "no default org" message.
|
|
220
|
+
The preflight is cached per process, so the later ``resolve_org`` call
|
|
221
|
+
does not probe again.
|
|
222
|
+
"""
|
|
223
|
+
_assert_show_access_token_capability()
|
|
224
|
+
argv = ["sf", "config", "get", "target-org", "--json"]
|
|
225
|
+
try:
|
|
226
|
+
proc = subprocess.run(
|
|
227
|
+
argv, capture_output=True, text=True, timeout=30, check=True,
|
|
228
|
+
)
|
|
229
|
+
except FileNotFoundError:
|
|
230
|
+
raise SystemExit(
|
|
231
|
+
"sf CLI not found on PATH — install Salesforce CLI first"
|
|
232
|
+
) from None
|
|
233
|
+
except subprocess.CalledProcessError as exc:
|
|
234
|
+
detail = (
|
|
235
|
+
_redact_text((exc.stderr or "").strip() or (exc.stdout or "").strip())
|
|
236
|
+
or "unknown error"
|
|
237
|
+
)
|
|
238
|
+
raise SystemExit(
|
|
239
|
+
f"{NO_DEFAULT_ORG_MSG}\n`sf config get target-org` failed: {detail}"
|
|
240
|
+
) from None
|
|
241
|
+
except subprocess.TimeoutExpired:
|
|
242
|
+
raise SystemExit(
|
|
243
|
+
f"{NO_DEFAULT_ORG_MSG}\n`sf config get target-org` timed out after 30s"
|
|
244
|
+
) from None
|
|
245
|
+
try:
|
|
246
|
+
payload = json.loads(proc.stdout or "")
|
|
247
|
+
except json.JSONDecodeError:
|
|
248
|
+
raise SystemExit(
|
|
249
|
+
f"{NO_DEFAULT_ORG_MSG}\n`sf config get target-org --json` returned "
|
|
250
|
+
f"non-JSON output: {_redact_text(proc.stdout.strip())[:200]}"
|
|
251
|
+
) from None
|
|
252
|
+
result = payload.get("result") if isinstance(payload, dict) else None
|
|
253
|
+
first = result[0] if isinstance(result, list) and result else {}
|
|
254
|
+
value = first.get("value") if isinstance(first, dict) else None
|
|
255
|
+
if not isinstance(value, str) or not value.strip():
|
|
256
|
+
raise SystemExit(NO_DEFAULT_ORG_MSG)
|
|
257
|
+
return value.strip()
|
|
104
258
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
259
|
+
|
|
260
|
+
def resolve_org(alias: str) -> tuple[str, str]:
|
|
261
|
+
"""Resolve instanceUrl + accessToken for the sf org alias.
|
|
262
|
+
|
|
263
|
+
Token retrieval is fail-fast (forcedotcom/cli#3560): the access token
|
|
264
|
+
comes ONLY from `sf org auth show-access-token --json --no-prompt`.
|
|
265
|
+
`sf org display --json --verbose` is used for non-secret metadata
|
|
266
|
+
(instanceUrl); any `accessToken` it carries is ignored.
|
|
108
267
|
|
|
109
268
|
Raises SystemExit on CLI failure — this is the one thing every
|
|
110
269
|
downstream operation depends on, so a clean early exit is friendlier
|
|
111
270
|
than a stack trace.
|
|
112
271
|
"""
|
|
113
|
-
# Step 1:
|
|
114
|
-
# the
|
|
115
|
-
|
|
272
|
+
# Step 1: capability preflight first, so a missing sf binary or missing
|
|
273
|
+
# command yields the actionable preflight error (cached once it passes).
|
|
274
|
+
_assert_show_access_token_capability()
|
|
275
|
+
|
|
276
|
+
# Step 2: org_display for instanceUrl (non-secret metadata only).
|
|
116
277
|
display = _run_sf_json(
|
|
117
278
|
["sf", "org", "display", "--target-org", alias, "--json", "--verbose"],
|
|
118
|
-
env=env,
|
|
119
279
|
)["result"]
|
|
120
280
|
instance_url = display.get("instanceUrl") or ""
|
|
121
281
|
if not instance_url:
|
|
@@ -123,37 +283,27 @@ def resolve_org(alias: str) -> tuple[str, str]:
|
|
|
123
283
|
f"sf org display returned no instanceUrl for alias {alias!r}"
|
|
124
284
|
)
|
|
125
285
|
|
|
126
|
-
# Step
|
|
127
|
-
# "is not a sf command" with returncode 0 (warning, not error), so
|
|
128
|
-
# we detect by parsing JSON shape. If the command is unknown the
|
|
129
|
-
# output isn't JSON; we let the json parse error trigger the fallback.
|
|
130
|
-
access_token = ""
|
|
286
|
+
# Step 3: dedicated command is the only token source.
|
|
131
287
|
try:
|
|
132
288
|
token_payload = _run_sf_json(
|
|
133
289
|
["sf", "org", "auth", "show-access-token",
|
|
134
290
|
"--target-org", alias, "--json", "--no-prompt"],
|
|
135
291
|
)
|
|
136
|
-
except (SystemExit, json.JSONDecodeError):
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
# try the legacy SF_TEMP_SHOW_SECRETS path via the org_display
|
|
146
|
-
# payload we already have.
|
|
147
|
-
if not access_token or _REDACTION_MARKER_FRAGMENT in access_token:
|
|
148
|
-
legacy = display.get("accessToken") or ""
|
|
149
|
-
if legacy and _REDACTION_MARKER_FRAGMENT not in legacy:
|
|
150
|
-
access_token = legacy
|
|
292
|
+
except (SystemExit, json.JSONDecodeError) as exc:
|
|
293
|
+
raise SystemExit(
|
|
294
|
+
f"could not retrieve access token for alias {alias!r} via "
|
|
295
|
+
"sf org auth show-access-token; ensure the org is authenticated "
|
|
296
|
+
f"(sf org login web --alias {alias}).\nDetail: {exc}"
|
|
297
|
+
) from exc
|
|
298
|
+
|
|
299
|
+
token_result = token_payload.get("result") or {}
|
|
300
|
+
access_token = token_result.get("accessToken") or ""
|
|
151
301
|
|
|
152
302
|
if not access_token or _REDACTION_MARKER_FRAGMENT in access_token:
|
|
153
303
|
raise SystemExit(
|
|
154
304
|
f"could not retrieve a usable access token for alias {alias!r} "
|
|
155
|
-
|
|
156
|
-
|
|
305
|
+
"via sf org auth show-access-token. Ensure sf CLI is logged in "
|
|
306
|
+
"for this org and the command returned a real token."
|
|
157
307
|
)
|
|
158
308
|
|
|
159
309
|
return instance_url, access_token
|
|
@@ -9,9 +9,11 @@ DC-only by design (no OTel path).
|
|
|
9
9
|
|
|
10
10
|
## CLI
|
|
11
11
|
|
|
12
|
-
python3 scripts/discover_sessions.py --org <alias> [options]
|
|
12
|
+
python3 scripts/discover_sessions.py [--org <alias>] [options]
|
|
13
13
|
|
|
14
|
-
Options (all optional
|
|
14
|
+
Options (all optional):
|
|
15
|
+
--org <alias> sf CLI org alias. Default: the sf CLI default target org
|
|
16
|
+
(`sf config get target-org`).
|
|
15
17
|
--since <expr> "last 2 hours" | "last 10" | "today" | "yesterday"
|
|
16
18
|
| "YYYY-MM-DD" | "YYYY-MM-DD to YYYY-MM-DD"
|
|
17
19
|
| explicit UTC/TZ datetime (RFC 3339). Default: last 24 hours.
|
|
@@ -55,7 +57,7 @@ from zoneinfo import ZoneInfo, ZoneInfoNotFoundError
|
|
|
55
57
|
|
|
56
58
|
sys.path.insert(0, str(Path(__file__).parent))
|
|
57
59
|
|
|
58
|
-
from dc import DCQueryError, load_sql, post, resolve_org
|
|
60
|
+
from dc import DCQueryError, default_target_org, load_sql, post, resolve_org
|
|
59
61
|
from _shared.sql import _escape_sql_literal
|
|
60
62
|
|
|
61
63
|
|
|
@@ -477,7 +479,8 @@ def main() -> int:
|
|
|
477
479
|
description="Find candidate Agentforce sessions via Data Cloud. "
|
|
478
480
|
"Prints a numbered picker; no artifacts written.",
|
|
479
481
|
)
|
|
480
|
-
ap.add_argument("--org",
|
|
482
|
+
ap.add_argument("--org", help="sf CLI org alias (the one you configured via `sf org login`). "
|
|
483
|
+
"Default: the sf CLI default target org")
|
|
481
484
|
ap.add_argument("--since", help='time range: "last 2 hours" | "today" | "yesterday" | '
|
|
482
485
|
'"YYYY-MM-DD" | "YYYY-MM-DD to YYYY-MM-DD" | ISO datetime. '
|
|
483
486
|
'Default: last 24 hours.')
|
|
@@ -519,7 +522,8 @@ def main() -> int:
|
|
|
519
522
|
limit=args.limit,
|
|
520
523
|
)
|
|
521
524
|
|
|
522
|
-
|
|
525
|
+
org = args.org or default_target_org()
|
|
526
|
+
instance_url, token = resolve_org(org)
|
|
523
527
|
try:
|
|
524
528
|
rows = post(sql, instance_url, token, "discover_sessions")
|
|
525
529
|
except DCQueryError as e:
|
|
@@ -544,7 +548,7 @@ def main() -> int:
|
|
|
544
548
|
print(render_picker(
|
|
545
549
|
rows=rows,
|
|
546
550
|
agent_by_sid=agent_by_sid,
|
|
547
|
-
org=
|
|
551
|
+
org=org,
|
|
548
552
|
tr=tr,
|
|
549
553
|
filters=filters,
|
|
550
554
|
composed_sql=sql,
|
|
@@ -23,7 +23,9 @@ Design contract:
|
|
|
23
23
|
- Rerunning the same session overwrites prior artifacts.
|
|
24
24
|
|
|
25
25
|
Invocation:
|
|
26
|
-
python3 scripts/fetch_dc.py --session <uuid> --org <alias> [--verbose]
|
|
26
|
+
python3 scripts/fetch_dc.py --session <uuid> [--org <alias>] [--verbose]
|
|
27
|
+
|
|
28
|
+
`--org` defaults to the sf CLI default target org (`sf config get target-org`).
|
|
27
29
|
|
|
28
30
|
After the waterfall finishes, the fetcher chains two downstream steps:
|
|
29
31
|
1. assemble_dc.main_for_session → dc._session_tree.json
|
|
@@ -66,7 +68,7 @@ from pathlib import Path
|
|
|
66
68
|
sys.path.insert(0, str(Path(__file__).parent))
|
|
67
69
|
|
|
68
70
|
from config import DATA_ROOT, paths, sql as _sql_mod
|
|
69
|
-
from dc import SQL_DIR, DCQueryError, load_sql, post, resolve_org
|
|
71
|
+
from dc import SQL_DIR, DCQueryError, default_target_org, load_sql, post, resolve_org
|
|
70
72
|
from storage import save
|
|
71
73
|
|
|
72
74
|
|
|
@@ -357,7 +359,7 @@ def main() -> int:
|
|
|
357
359
|
help="AI-agent session UUID, OR a Salesforce MessagingSession id "
|
|
358
360
|
"(0Mw... prefix). Messaging ids are resolved to the UUID "
|
|
359
361
|
"via a one-row DC lookup before the waterfall starts.")
|
|
360
|
-
ap.add_argument("--org",
|
|
362
|
+
ap.add_argument("--org", help="sf org alias (default: the sf CLI default target org)")
|
|
361
363
|
ap.add_argument("--verbose", action="store_true", help="dump each SQL before POST")
|
|
362
364
|
ap.add_argument("--no-assemble", action="store_true",
|
|
363
365
|
help="skip tree assembly after fetch")
|
|
@@ -371,6 +373,20 @@ def main() -> int:
|
|
|
371
373
|
|
|
372
374
|
_preflight_templates()
|
|
373
375
|
|
|
376
|
+
# No --org means the sf CLI default target org. If none is set, surface
|
|
377
|
+
# it through the DC-access-denied contract (reason "no_org", exit 10
|
|
378
|
+
# headless) — the same path an unresolvable alias takes.
|
|
379
|
+
org = args.org
|
|
380
|
+
if not org:
|
|
381
|
+
try:
|
|
382
|
+
org = default_target_org()
|
|
383
|
+
except SystemExit as e:
|
|
384
|
+
return _handle_dc_access_denied(
|
|
385
|
+
DcAccessDenied("no_org", str(e)),
|
|
386
|
+
session_id=args.session,
|
|
387
|
+
is_tty=sys.stdin.isatty(),
|
|
388
|
+
)
|
|
389
|
+
|
|
374
390
|
# Accept either a UUID or a MessagingSession id (0Mw...). The resolver
|
|
375
391
|
# passes UUIDs through unchanged; on messaging ids it tries disk first
|
|
376
392
|
# (any prior fetch left dc.sessions.json behind under DATA_ROOT), and
|
|
@@ -380,7 +396,7 @@ def main() -> int:
|
|
|
380
396
|
# On multi-match or zero-match the resolver exits with a diagnostic.
|
|
381
397
|
from resolve_session import is_messaging_id, resolve_disk_or_live
|
|
382
398
|
input_id = args.session
|
|
383
|
-
session_id = resolve_disk_or_live(input_id, org=
|
|
399
|
+
session_id = resolve_disk_or_live(input_id, org=org)
|
|
384
400
|
if is_messaging_id(input_id):
|
|
385
401
|
_log(f"resolved messaging id {input_id} → AiAgentSession {session_id}")
|
|
386
402
|
|
|
@@ -390,7 +406,7 @@ def main() -> int:
|
|
|
390
406
|
# emits either an interactive prompt or a JSON preamble depending on
|
|
391
407
|
# tty presence, then exits with EXIT_DC_ACCESS_DENIED (10).
|
|
392
408
|
try:
|
|
393
|
-
instance_url, token = preflight_dc_access(session_id,
|
|
409
|
+
instance_url, token = preflight_dc_access(session_id, org)
|
|
394
410
|
except DcAccessDenied as exc:
|
|
395
411
|
return _handle_dc_access_denied(
|
|
396
412
|
exc,
|
|
@@ -402,7 +418,7 @@ def main() -> int:
|
|
|
402
418
|
|
|
403
419
|
ctx = {
|
|
404
420
|
"session_id": session_id,
|
|
405
|
-
"org_alias":
|
|
421
|
+
"org_alias": org,
|
|
406
422
|
"instance_url": instance_url,
|
|
407
423
|
"token": token,
|
|
408
424
|
"verbose": args.verbose,
|
|
@@ -21,7 +21,8 @@ specific UUID.
|
|
|
21
21
|
|
|
22
22
|
## Two resolution modes
|
|
23
23
|
|
|
24
|
-
1. **Live** — query DC
|
|
24
|
+
1. **Live** — query DC against `--org` (CLI: defaults to the sf CLI default
|
|
25
|
+
target org). Used by `fetch_dc.py` at the
|
|
25
26
|
top of the pipeline (before any artifacts exist on disk).
|
|
26
27
|
2. **Disk-first** — scan `DATA_ROOT/*/dc.sessions.json` for a row whose
|
|
27
28
|
`ssot__RelatedMessagingSessionId__c` matches. No DC call, no `--org`
|
|
@@ -31,7 +32,7 @@ specific UUID.
|
|
|
31
32
|
|
|
32
33
|
## CLI
|
|
33
34
|
|
|
34
|
-
python3 scripts/resolve_session.py --id <uuid|msg_id> --org <alias>
|
|
35
|
+
python3 scripts/resolve_session.py --id <uuid|msg_id> [--org <alias>]
|
|
35
36
|
|
|
36
37
|
Prints the resolved UUID to stdout on single-match (or pass-through).
|
|
37
38
|
Non-zero exit with diagnostics on zero-match and multi-match.
|
|
@@ -47,7 +48,7 @@ from typing import List, Optional
|
|
|
47
48
|
sys.path.insert(0, str(Path(__file__).parent))
|
|
48
49
|
|
|
49
50
|
from config import DATA_ROOT
|
|
50
|
-
from dc import load_sql, post, resolve_org
|
|
51
|
+
from dc import default_target_org, load_sql, post, resolve_org
|
|
51
52
|
|
|
52
53
|
|
|
53
54
|
# NOT_SET sentinel set. Matches fetch_dc.py:41; keep in sync.
|
|
@@ -224,7 +225,8 @@ def main() -> int:
|
|
|
224
225
|
)
|
|
225
226
|
ap.add_argument("--id", required=True,
|
|
226
227
|
help="Either the AI-agent session UUID or the MessagingSession id (0Mw...)")
|
|
227
|
-
ap.add_argument("--org", help="sf org alias
|
|
228
|
+
ap.add_argument("--org", help="sf org alias for the live DC lookup when input is 0Mw... "
|
|
229
|
+
"(default: the sf CLI default target org)")
|
|
228
230
|
ap.add_argument("--disk-only", action="store_true",
|
|
229
231
|
help="Only scan DATA_ROOT/*/dc.sessions.json; no DC query")
|
|
230
232
|
# Runtime-agnostic path overrides; default to ~/.vibe/...
|
|
@@ -243,19 +245,25 @@ def main() -> int:
|
|
|
243
245
|
return 1
|
|
244
246
|
print(found)
|
|
245
247
|
return 0
|
|
246
|
-
|
|
247
|
-
|
|
248
|
+
org = args.org
|
|
249
|
+
if not org:
|
|
250
|
+
# Try disk first as a convenience; on a miss, fall back to the sf CLI
|
|
251
|
+
# default target org for the live lookup, and only error if that
|
|
252
|
+
# is unset too.
|
|
248
253
|
disk = resolve_from_disk(args.id)
|
|
249
254
|
if disk is not None:
|
|
250
255
|
print(disk)
|
|
251
256
|
return 0
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
257
|
+
try:
|
|
258
|
+
org = default_target_org()
|
|
259
|
+
except SystemExit as e:
|
|
260
|
+
print(
|
|
261
|
+
f"resolve_session: {args.id!r} not found on disk; --org <alias> required "
|
|
262
|
+
f"for a live DC lookup ({e})",
|
|
263
|
+
file=sys.stderr,
|
|
264
|
+
)
|
|
265
|
+
return 2
|
|
266
|
+
uuid = resolve(args.id, org=org)
|
|
259
267
|
print(uuid)
|
|
260
268
|
return 0
|
|
261
269
|
|