@tenderprompt/cli 0.1.24 → 0.1.25
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/README.md +15 -0
- package/dist/artifact-memory.js +4 -3
- package/dist/index.js +242 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -43,6 +43,7 @@ session:
|
|
|
43
43
|
analytics history, app database rows, secrets, or release history
|
|
44
44
|
- run server-validated chart specs and export aggregate rows
|
|
45
45
|
- generate starter analytics suggestions
|
|
46
|
+
- print a non-mutating default analytics provisioning plan for generated apps
|
|
46
47
|
- create, list, update, and delete saved analytics dashboards and charts, with
|
|
47
48
|
`--dry-run` available for write previews
|
|
48
49
|
|
|
@@ -79,6 +80,13 @@ For agents, keep the pattern simple:
|
|
|
79
80
|
6. call `preview`, `publish --dry-run`, then `publish --confirm publish` only
|
|
80
81
|
when the user asked to publish
|
|
81
82
|
|
|
83
|
+
For replacement work, run `tender app analytics authoring --json` before adding
|
|
84
|
+
or repairing instrumentation. Its agent guidance tells agents to inspect the
|
|
85
|
+
existing shopper surface before source edits, keep operator analytics out of
|
|
86
|
+
shopper UI, and treat default analytics plus saved starter dashboard charts as
|
|
87
|
+
part of generated-app delivery unless the user opts out or there is a concrete
|
|
88
|
+
blocker.
|
|
89
|
+
|
|
82
90
|
## Auth
|
|
83
91
|
|
|
84
92
|
Use the device login flow to mint a local token:
|
|
@@ -185,6 +193,7 @@ agents:
|
|
|
185
193
|
|
|
186
194
|
```bash
|
|
187
195
|
tender app analytics capabilities artifact_123 --include-catalog --range 30d --json
|
|
196
|
+
tender app analytics provision artifact_123 --from-app --json
|
|
188
197
|
```
|
|
189
198
|
|
|
190
199
|
That response tells the agent:
|
|
@@ -201,6 +210,8 @@ Common read-only commands:
|
|
|
201
210
|
```bash
|
|
202
211
|
tender app analytics summary artifact_123 --range 30d --json
|
|
203
212
|
|
|
213
|
+
tender app analytics provision artifact_123 --from-app --json
|
|
214
|
+
|
|
204
215
|
tender app analytics query artifact_123 --spec chart.json --json
|
|
205
216
|
|
|
206
217
|
tender app analytics query artifact_123 --spec - --json < chart.json
|
|
@@ -256,6 +267,10 @@ explicit:
|
|
|
256
267
|
tender app analytics charts list artifact_123 --dashboard analytics_dashboard_123 --json
|
|
257
268
|
```
|
|
258
269
|
|
|
270
|
+
`analytics provision --from-app` is a guided plan in this release, not a hidden
|
|
271
|
+
write. It returns starter chart specs, write-preview commands, write commands,
|
|
272
|
+
blockers, and the chart-list completion proof an external agent should report.
|
|
273
|
+
|
|
259
274
|
Agents should combine `capabilities --include-catalog` with local source-code
|
|
260
275
|
inspection. For example, inspect where the app calls
|
|
261
276
|
`__TP_ANALYTICS.invoke(...)`, propose a chart spec, validate it with
|
package/dist/artifact-memory.js
CHANGED
|
@@ -100,7 +100,8 @@ function assertUsefulMemoryText(input) {
|
|
|
100
100
|
if (lineCount > 240 || byteLength(total) > ARTIFACT_MEMORY_ENTRY_MAX_BYTES) {
|
|
101
101
|
throw new Error(`Memory entries are limited to ${ARTIFACT_MEMORY_ENTRY_MAX_BYTES} bytes. Summarize the relevant context instead.\nNext: tender memory handoff --reason "Need Tender support" --summary "Current blocker and what was tried"`);
|
|
102
102
|
}
|
|
103
|
-
|
|
103
|
+
const allowsLongBody = input.kind === 'summary' || input.kind === 'support_handoff' || input.kind === 'reflection';
|
|
104
|
+
if (lineCount > 40 && !allowsLongBody) {
|
|
104
105
|
throw new Error('Memory entries should be bounded summaries, not raw transcript dumps.\nNext: tender memory add --kind summary --summary "Compact the useful context" --body "Goal, changes, failures, and next step"');
|
|
105
106
|
}
|
|
106
107
|
}
|
|
@@ -162,14 +163,14 @@ async function readExistingNote(input) {
|
|
|
162
163
|
return result.exitCode === 0 ? result.stdout : '';
|
|
163
164
|
}
|
|
164
165
|
export async function appendArtifactMemoryNote(input) {
|
|
165
|
-
|
|
166
|
+
const normalizedKind = normalizeArtifactMemoryKind(input.kind);
|
|
167
|
+
assertUsefulMemoryText({ ...input, kind: normalizedKind.kind });
|
|
166
168
|
const commitSha = input.commitSha ?? (await readArtifactMemoryHead(input));
|
|
167
169
|
const artifactId = input.artifactId ?? (await inferArtifactIdFromRemote(input));
|
|
168
170
|
if (!artifactId) {
|
|
169
171
|
throw new Error('Artifact memory requires an artifact id. Pass --artifact or run inside a checkout with a Tender artifact remote.\nNext: tender app git setup <app-id> --dir .');
|
|
170
172
|
}
|
|
171
173
|
const sessionId = await readArtifactMemorySessionId(input);
|
|
172
|
-
const normalizedKind = normalizeArtifactMemoryKind(input.kind);
|
|
173
174
|
const redactedSummary = redactArtifactMemoryText(input.summary.trim());
|
|
174
175
|
const redactedBody = input.body?.trim() ? redactArtifactMemoryText(input.body.trim()) : null;
|
|
175
176
|
const warnings = [
|
package/dist/index.js
CHANGED
|
@@ -34,6 +34,61 @@ const CLI_PACKAGE_VERSION = readCliPackageVersion();
|
|
|
34
34
|
const ANALYTICS_AUTHORING_PLAYBOOK_ID = 'analytics-event-authoring';
|
|
35
35
|
const ANALYTICS_AUTHORING_COMMAND = 'tender app analytics authoring --json';
|
|
36
36
|
const ANALYTICS_AUTHORING_PLAYBOOK_COMMAND = `tender playbooks get ${ANALYTICS_AUTHORING_PLAYBOOK_ID} --json`;
|
|
37
|
+
const ANALYTICS_AGENT_GUIDANCE = {
|
|
38
|
+
generatedAppDelivery: {
|
|
39
|
+
defaultAnalytics: 'Generated apps should emit useful Tender analytics events and provision saved starter dashboard charts by default unless the user opts out or a concrete blocker is recorded.',
|
|
40
|
+
skipOnlyWhen: ['The user explicitly opts out.', 'A concrete platform or data blocker is reported.'],
|
|
41
|
+
},
|
|
42
|
+
replacementBaseline: {
|
|
43
|
+
requiredBeforeSourceEdits: true,
|
|
44
|
+
guidance: 'Replacement work must inspect and interact with the existing customer-facing surface before source edits, or record the concrete blocker.',
|
|
45
|
+
browserToolPriority: [
|
|
46
|
+
'Codex in-app browser:browser skill',
|
|
47
|
+
'agent-browser',
|
|
48
|
+
'Chrome DevTools MCP',
|
|
49
|
+
'Playwright',
|
|
50
|
+
'another browser-capable tool',
|
|
51
|
+
],
|
|
52
|
+
},
|
|
53
|
+
shopperOperatorBoundary: {
|
|
54
|
+
guidance: 'Tender analytics dashboards, A/B reports, sessions, and internal counters are operator-facing Tender surfaces, not shopper-facing app UI.',
|
|
55
|
+
shopperUiMustNotInclude: [
|
|
56
|
+
'analytics dashboards',
|
|
57
|
+
'A/B reports',
|
|
58
|
+
'sessions tables',
|
|
59
|
+
'internal counters',
|
|
60
|
+
'dashboard controls',
|
|
61
|
+
'shopper-callable analytics summary routes',
|
|
62
|
+
],
|
|
63
|
+
adminSurfaceException: 'Only build an admin or operator surface when the user explicitly asks for one, and secure it so shopper traffic cannot read internal analytics.',
|
|
64
|
+
},
|
|
65
|
+
dashboardCompletion: {
|
|
66
|
+
completeWhen: [
|
|
67
|
+
'A Tender dashboard exists or is reused.',
|
|
68
|
+
'Required queryable properties are active, already queryable, or blocked with an actionable reason.',
|
|
69
|
+
'Saved starter charts exist for the app journey.',
|
|
70
|
+
'The saved chart list has been queried and returns the chart names or ids.',
|
|
71
|
+
],
|
|
72
|
+
notCompleteWhen: ['Only an empty dashboard shell exists.'],
|
|
73
|
+
proofCommand: 'tender app analytics charts list <app-id> --dashboard <dashboard-id> --json',
|
|
74
|
+
},
|
|
75
|
+
starterDashboardCommands: [
|
|
76
|
+
'tender app analytics authoring --json',
|
|
77
|
+
'tender playbooks get analytics-event-authoring --json',
|
|
78
|
+
'tender app analytics charts templates --json',
|
|
79
|
+
'tender app analytics properties activate <app-id> --event <event-name> --property <property-key> --type dimension --dry-run --json',
|
|
80
|
+
'tender app analytics dashboards <app-id> --create "Agent dashboard" --dry-run --json',
|
|
81
|
+
'tender app analytics charts create <app-id> --dashboard <dashboard-id> --title <title> --spec chart.json --dry-run --json',
|
|
82
|
+
'tender app analytics charts list <app-id> --dashboard <dashboard-id> --json',
|
|
83
|
+
],
|
|
84
|
+
finalAnswerEvidence: [
|
|
85
|
+
'baseline inspection scope or blocker',
|
|
86
|
+
'published URL or preview status',
|
|
87
|
+
'Tender dashboard id',
|
|
88
|
+
'saved chart names or ids from charts list',
|
|
89
|
+
'clear split between shopper-facing UI and operator-facing analytics',
|
|
90
|
+
],
|
|
91
|
+
};
|
|
37
92
|
class TenderCliUsageError extends Error {
|
|
38
93
|
constructor(message) {
|
|
39
94
|
super(message);
|
|
@@ -350,12 +405,12 @@ Commands:
|
|
|
350
405
|
Rebuild the preview and optionally stream lifecycle events
|
|
351
406
|
tender app preview status <app-id>
|
|
352
407
|
Show preview job status by latest, commit, or job id
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
408
|
+
tender app preview watch <app-id>
|
|
409
|
+
Replay lifecycle events by latest, commit, or job id
|
|
410
|
+
tender app agent heartbeat <app-id>
|
|
411
|
+
Send a concise agent status update to the workspace
|
|
412
|
+
tender app publish <app-id>
|
|
413
|
+
Publish after dry-run or explicit confirmation
|
|
359
414
|
tender app publish status <app-id>
|
|
360
415
|
Show publish job status by job id
|
|
361
416
|
tender app publish watch <app-id>
|
|
@@ -372,6 +427,8 @@ Commands:
|
|
|
372
427
|
Run a server-validated chart spec
|
|
373
428
|
tender app analytics suggestions <app-id>
|
|
374
429
|
Generate useful starter chart suggestions
|
|
430
|
+
tender app analytics provision <app-id>
|
|
431
|
+
Print a starter dashboard provisioning plan
|
|
375
432
|
tender app analytics dashboards <app-id>
|
|
376
433
|
List or create saved dashboards
|
|
377
434
|
tender app analytics charts create <app-id>
|
|
@@ -537,6 +594,7 @@ Commands:
|
|
|
537
594
|
tender app analytics capabilities <app-id> Describe agent-safe analytics capabilities
|
|
538
595
|
tender app analytics suggestions <app-id> Generate starter chart suggestions
|
|
539
596
|
tender app analytics exact-funnel <app-id> Run exact unit funnel analysis
|
|
597
|
+
tender app analytics provision <app-id> Print a starter dashboard provisioning plan
|
|
540
598
|
tender app analytics dashboards <app-id> List or create dashboards
|
|
541
599
|
tender app analytics export <kind> <app-id> Export catalog metadata or query rows
|
|
542
600
|
tender app analytics charts templates Print reusable chart spec templates
|
|
@@ -557,6 +615,7 @@ Examples:
|
|
|
557
615
|
tender app analytics export catalog artifact_123 --range 30d --json
|
|
558
616
|
tender app analytics export query artifact_123 --spec chart.json --format csv
|
|
559
617
|
tender app analytics suggestions artifact_123 --range 2026-04-01..2026-04-30 --json
|
|
618
|
+
tender app analytics provision artifact_123 --from-app --json
|
|
560
619
|
tender app analytics dashboards artifact_123 --create "Agent dashboard" --json
|
|
561
620
|
tender app analytics charts templates --json
|
|
562
621
|
tender app analytics charts create artifact_123 --dashboard analytics_dashboard_123 --title "Signup funnel" --spec unit-funnel.json --json
|
|
@@ -572,6 +631,10 @@ function analyticsAuthoringHelp() {
|
|
|
572
631
|
Prints the current generated-app analytics event authoring contract. This command
|
|
573
632
|
does not require an app id, checkout, API token, or installed skill.
|
|
574
633
|
|
|
634
|
+
Agent guidance includes default generated-app analytics, replacement baseline
|
|
635
|
+
inspection, shopper/operator surface separation, and dashboard chart-list
|
|
636
|
+
completion criteria.
|
|
637
|
+
|
|
575
638
|
Examples:
|
|
576
639
|
tender app analytics authoring --json`;
|
|
577
640
|
}
|
|
@@ -638,6 +701,18 @@ dashboard page loads.
|
|
|
638
701
|
Examples:
|
|
639
702
|
tender app analytics exact-funnel artifact_123 --flow checkout_flow --steps started,completed --range 30d --json`;
|
|
640
703
|
}
|
|
704
|
+
function analyticsProvisionHelp() {
|
|
705
|
+
return `Usage: tender app analytics provision <app-id> --from-app [--dashboard-name <name>] [--base-url <url>] [--token <token>] [--profile <name>] [--json]
|
|
706
|
+
|
|
707
|
+
Prints a machine-readable provisioning plan for the default generated-app
|
|
708
|
+
analytics delivery contract. This command does not mutate dashboards yet; it
|
|
709
|
+
returns the exact commands, starter chart specs, completion criteria, and
|
|
710
|
+
blockers an external coding agent should follow.
|
|
711
|
+
|
|
712
|
+
Examples:
|
|
713
|
+
tender app analytics provision artifact_123 --from-app --json
|
|
714
|
+
tender app analytics provision artifact_123 --from-app --dashboard-name "Recommendation dashboard" --json`;
|
|
715
|
+
}
|
|
641
716
|
function analyticsDashboardsHelp() {
|
|
642
717
|
return `Usage: tender app analytics dashboards <app-id> [--create <name>] [--dry-run] [--base-url <url>] [--token <token>] [--profile <name>] [--json]
|
|
643
718
|
|
|
@@ -1097,6 +1172,15 @@ Examples:
|
|
|
1097
1172
|
tender app agent heartbeat artifact_123 --source claude-code --status needs_attention --summary "Waiting for an API key decision" --requested-action answer_question --json
|
|
1098
1173
|
tender app agent heartbeat artifact_123 --input - --json < heartbeat.json`;
|
|
1099
1174
|
}
|
|
1175
|
+
function appAgentHelp() {
|
|
1176
|
+
return `Usage: tender app agent <command>
|
|
1177
|
+
|
|
1178
|
+
Commands:
|
|
1179
|
+
heartbeat <app-id> Send a concise agent status update to the workspace.
|
|
1180
|
+
|
|
1181
|
+
Examples:
|
|
1182
|
+
tender app agent heartbeat artifact_123 --source codex --status working --summary "Reading files" --json`;
|
|
1183
|
+
}
|
|
1100
1184
|
function publishStatusHelp() {
|
|
1101
1185
|
return `Usage: tender app publish status <app-id> --job <job-id> [--base-url <url>] [--token <token>] [--profile <name>] [--json]
|
|
1102
1186
|
|
|
@@ -1174,6 +1258,7 @@ function tenderCliCapabilities() {
|
|
|
1174
1258
|
playbookCommand: ANALYTICS_AUTHORING_PLAYBOOK_COMMAND,
|
|
1175
1259
|
doctorCommand: 'tender app doctor --dir <dir> --json',
|
|
1176
1260
|
purpose: 'Keep generated app analytics events compatible with Tender dashboards and unit funnels.',
|
|
1261
|
+
guidance: ANALYTICS_AGENT_GUIDANCE,
|
|
1177
1262
|
},
|
|
1178
1263
|
description: 'Agent-safe Tender App source, lifecycle, analytics, and local scaffold controls.',
|
|
1179
1264
|
discovery: {
|
|
@@ -1185,6 +1270,7 @@ function tenderCliCapabilities() {
|
|
|
1185
1270
|
'tender memory --help',
|
|
1186
1271
|
'tender playbooks --help',
|
|
1187
1272
|
'tender app --help',
|
|
1273
|
+
'tender app agent --help',
|
|
1188
1274
|
'tender app agent heartbeat --help',
|
|
1189
1275
|
'tender app share --help',
|
|
1190
1276
|
'tender app claim --help',
|
|
@@ -1286,6 +1372,7 @@ function tenderCliCapabilities() {
|
|
|
1286
1372
|
commands: [
|
|
1287
1373
|
ANALYTICS_AUTHORING_COMMAND,
|
|
1288
1374
|
ANALYTICS_AUTHORING_PLAYBOOK_COMMAND,
|
|
1375
|
+
'tender app analytics provision <artifact-id> --from-app --json',
|
|
1289
1376
|
'tender app analytics capabilities <artifact-id> --include-catalog --range 30d --json',
|
|
1290
1377
|
'tender app analytics charts templates --json',
|
|
1291
1378
|
'tender app analytics query <artifact-id> --spec chart.json --json',
|
|
@@ -1300,10 +1387,14 @@ function tenderCliCapabilities() {
|
|
|
1300
1387
|
],
|
|
1301
1388
|
notes: [
|
|
1302
1389
|
'Run authoring before adding or repairing analytics instrumentation; use capabilities for artifact-scoped read/query details.',
|
|
1390
|
+
'Generated apps should get useful Tender analytics events and saved starter dashboard charts by default unless the user opts out or a concrete blocker is recorded.',
|
|
1391
|
+
'For replacement work, inspect the baseline customer-facing page or widget before source edits; Codex should prefer browser:browser when available.',
|
|
1392
|
+
'Tender analytics dashboards are operator-facing surfaces; do not render dashboards, A/B reports, sessions, or internal counters in shopper UI unless the user explicitly requests a secured admin surface.',
|
|
1303
1393
|
'Combine CLI capabilities with local source inspection of analytics calls.',
|
|
1304
1394
|
'Validate chart specs with query before creating or updating saved charts.',
|
|
1305
1395
|
'Property chart create/update commands automatically make missing custom event properties queryable when the spec has an event_name = filter.',
|
|
1306
1396
|
'Ad hoc query is read-only; if it reports a missing dashboard-query property, activate the property first or save the chart through charts create/update.',
|
|
1397
|
+
'Dashboard setup is not complete until saved charts exist and tender app analytics charts list returns chart names or ids.',
|
|
1307
1398
|
'Use list before writes so agents can avoid duplicates and explain the exact chart they are changing.',
|
|
1308
1399
|
],
|
|
1309
1400
|
},
|
|
@@ -1450,6 +1541,12 @@ function tenderCliCapabilities() {
|
|
|
1450
1541
|
requiresAuth: false,
|
|
1451
1542
|
writes: false,
|
|
1452
1543
|
},
|
|
1544
|
+
{
|
|
1545
|
+
command: 'tender app analytics provision <artifact-id> --from-app --json',
|
|
1546
|
+
purpose: 'Print a guided starter dashboard provisioning plan with chart-list completion proof.',
|
|
1547
|
+
requiresAuth: false,
|
|
1548
|
+
writes: false,
|
|
1549
|
+
},
|
|
1453
1550
|
{
|
|
1454
1551
|
command: 'tender app analytics properties list <artifact-id> --json',
|
|
1455
1552
|
purpose: 'List custom event properties available to dashboard queries.',
|
|
@@ -4103,6 +4200,35 @@ function parseAnalyticsDashboardsArgs(args) {
|
|
|
4103
4200
|
}
|
|
4104
4201
|
return { command: 'app analytics dashboards', artifactId, name, dryRun, ...parsed };
|
|
4105
4202
|
}
|
|
4203
|
+
function parseAnalyticsProvisionArgs(args) {
|
|
4204
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
4205
|
+
return { command: 'help', topic: 'app analytics provision' };
|
|
4206
|
+
}
|
|
4207
|
+
const artifactId = args[0];
|
|
4208
|
+
if (!artifactId || artifactId.startsWith('-')) {
|
|
4209
|
+
throw new TenderCliUsageError('app id is required. Example: tender app analytics provision <app-id> --from-app --json');
|
|
4210
|
+
}
|
|
4211
|
+
const parsed = parseAnalyticsCommonArgs(args, 1);
|
|
4212
|
+
let fromApp = false;
|
|
4213
|
+
let dashboardName = 'Agent dashboard';
|
|
4214
|
+
for (let index = 0; index < parsed.remaining.length; index += 1) {
|
|
4215
|
+
const arg = parsed.remaining[index];
|
|
4216
|
+
if (arg === '--from-app') {
|
|
4217
|
+
fromApp = true;
|
|
4218
|
+
continue;
|
|
4219
|
+
}
|
|
4220
|
+
if (arg === '--dashboard-name') {
|
|
4221
|
+
dashboardName = parseRequiredFlagValue(parsed.remaining[index + 1], '--dashboard-name');
|
|
4222
|
+
index += 1;
|
|
4223
|
+
continue;
|
|
4224
|
+
}
|
|
4225
|
+
throw new TenderCliUsageError(`Unknown analytics provision option: ${arg}`);
|
|
4226
|
+
}
|
|
4227
|
+
if (!fromApp) {
|
|
4228
|
+
throw new TenderCliUsageError('--from-app is required. Example: tender app analytics provision artifact_123 --from-app --json');
|
|
4229
|
+
}
|
|
4230
|
+
return { command: 'app analytics provision', artifactId, fromApp, dashboardName, ...parsed };
|
|
4231
|
+
}
|
|
4106
4232
|
function parseAnalyticsChartsTemplatesArgs(args) {
|
|
4107
4233
|
if (args.includes('--help') || args.includes('-h')) {
|
|
4108
4234
|
return { command: 'help', topic: 'app analytics charts templates' };
|
|
@@ -4222,6 +4348,7 @@ function analyticsAuthoringContract() {
|
|
|
4222
4348
|
'analytics_unstable_unit_id',
|
|
4223
4349
|
],
|
|
4224
4350
|
},
|
|
4351
|
+
agentGuidance: ANALYTICS_AGENT_GUIDANCE,
|
|
4225
4352
|
analyticsAuthoring: {
|
|
4226
4353
|
payloadShape: {
|
|
4227
4354
|
event: 'custom_event_name',
|
|
@@ -4293,6 +4420,8 @@ function analyticsAuthoringContract() {
|
|
|
4293
4420
|
},
|
|
4294
4421
|
],
|
|
4295
4422
|
charting: {
|
|
4423
|
+
starterDashboardCommands: ANALYTICS_AGENT_GUIDANCE.starterDashboardCommands,
|
|
4424
|
+
completionProof: ANALYTICS_AGENT_GUIDANCE.dashboardCompletion.proofCommand,
|
|
4296
4425
|
unitFunnel: 'After traffic exists, use tender app analytics capabilities <app-id> --include-catalog --json and create version 2 unit_step_count funnel specs from observedFlows and observedUnitTypes.',
|
|
4297
4426
|
exactAudit: 'Use tender app analytics exact-funnel <app-id> --flow <flow-id> --steps <step-a,step-b> --json for repair and low-volume audits.',
|
|
4298
4427
|
},
|
|
@@ -4648,6 +4777,100 @@ function runAnalyticsChartsTemplates(command, io) {
|
|
|
4648
4777
|
}
|
|
4649
4778
|
return 0;
|
|
4650
4779
|
}
|
|
4780
|
+
function quoteCliArgument(value) {
|
|
4781
|
+
return JSON.stringify(value);
|
|
4782
|
+
}
|
|
4783
|
+
function buildAnalyticsProvisionPayload(command) {
|
|
4784
|
+
const starterTemplateIds = new Set(['daily_custom_events', 'top_custom_events']);
|
|
4785
|
+
const starterCharts = analyticsChartTemplates()
|
|
4786
|
+
.filter((template) => starterTemplateIds.has(template.id))
|
|
4787
|
+
.map((template) => ({
|
|
4788
|
+
templateId: template.id,
|
|
4789
|
+
title: template.title,
|
|
4790
|
+
purpose: template.purpose,
|
|
4791
|
+
spec: template.spec,
|
|
4792
|
+
}));
|
|
4793
|
+
const dashboardName = quoteCliArgument(command.dashboardName);
|
|
4794
|
+
return {
|
|
4795
|
+
ok: true,
|
|
4796
|
+
command: command.command,
|
|
4797
|
+
version: 1,
|
|
4798
|
+
artifactId: command.artifactId,
|
|
4799
|
+
mode: 'guided_provisioning_plan',
|
|
4800
|
+
writes: false,
|
|
4801
|
+
fromApp: command.fromApp,
|
|
4802
|
+
dashboardName: command.dashboardName,
|
|
4803
|
+
description: 'Machine-readable starter dashboard provisioning plan for external coding agents. This command does not mutate dashboards yet.',
|
|
4804
|
+
agentGuidance: ANALYTICS_AGENT_GUIDANCE,
|
|
4805
|
+
starterCharts,
|
|
4806
|
+
steps: [
|
|
4807
|
+
{
|
|
4808
|
+
id: 'read_authoring_contract',
|
|
4809
|
+
command: ANALYTICS_AUTHORING_COMMAND,
|
|
4810
|
+
completion: 'Generated app analytics payload contract and surface boundary are loaded.',
|
|
4811
|
+
},
|
|
4812
|
+
{
|
|
4813
|
+
id: 'inspect_app_analytics',
|
|
4814
|
+
commands: [
|
|
4815
|
+
`tender app analytics capabilities ${command.artifactId} --include-catalog --range 30d --json`,
|
|
4816
|
+
'tender app doctor --dir . --json',
|
|
4817
|
+
],
|
|
4818
|
+
completion: 'Observed events, unit/flow metadata, existing dashboards, and local analytics diagnostics are known.',
|
|
4819
|
+
},
|
|
4820
|
+
{
|
|
4821
|
+
id: 'choose_starter_charts',
|
|
4822
|
+
command: 'tender app analytics charts templates --json',
|
|
4823
|
+
defaultTemplates: ['daily_custom_events', 'top_custom_events'],
|
|
4824
|
+
completion: 'Starter chart specs are adapted to observed events or accepted as generic app-owned event charts.',
|
|
4825
|
+
},
|
|
4826
|
+
{
|
|
4827
|
+
id: 'create_or_reuse_dashboard',
|
|
4828
|
+
dryRunCommand: `tender app analytics dashboards ${command.artifactId} --create ${dashboardName} --dry-run --json`,
|
|
4829
|
+
writeCommand: `tender app analytics dashboards ${command.artifactId} --create ${dashboardName} --json`,
|
|
4830
|
+
completion: 'A dashboard id is available, either reused from capabilities or returned by the create command.',
|
|
4831
|
+
},
|
|
4832
|
+
{
|
|
4833
|
+
id: 'validate_chart_specs',
|
|
4834
|
+
command: `tender app analytics query ${command.artifactId} --spec chart.json --json`,
|
|
4835
|
+
completion: 'Each chart spec is server-validated before it is saved.',
|
|
4836
|
+
},
|
|
4837
|
+
{
|
|
4838
|
+
id: 'create_saved_charts',
|
|
4839
|
+
dryRunCommand: `tender app analytics charts create ${command.artifactId} --dashboard <dashboard-id> --title <title> --spec chart.json --dry-run --json`,
|
|
4840
|
+
writeCommand: `tender app analytics charts create ${command.artifactId} --dashboard <dashboard-id> --title <title> --spec chart.json --json`,
|
|
4841
|
+
completion: 'Saved chart ids exist for starter charts, or a concrete blocker is reported.',
|
|
4842
|
+
},
|
|
4843
|
+
{
|
|
4844
|
+
id: 'prove_completion',
|
|
4845
|
+
command: `tender app analytics charts list ${command.artifactId} --dashboard <dashboard-id> --json`,
|
|
4846
|
+
completion: 'The chart list returns saved chart names or ids; an empty dashboard shell is not complete.',
|
|
4847
|
+
},
|
|
4848
|
+
],
|
|
4849
|
+
completionCriteria: ANALYTICS_AGENT_GUIDANCE.dashboardCompletion.completeWhen,
|
|
4850
|
+
blockers: [
|
|
4851
|
+
'User explicitly opted out of analytics.',
|
|
4852
|
+
'No meaningful generated-app journey exists to instrument yet.',
|
|
4853
|
+
'App source cannot be inspected from the current checkout.',
|
|
4854
|
+
'Dashboard/chart API returns an actionable auth, validation, or property activation error.',
|
|
4855
|
+
],
|
|
4856
|
+
finalAnswerEvidence: ANALYTICS_AGENT_GUIDANCE.finalAnswerEvidence,
|
|
4857
|
+
};
|
|
4858
|
+
}
|
|
4859
|
+
function runAnalyticsProvision(command, io) {
|
|
4860
|
+
const payload = buildAnalyticsProvisionPayload(command);
|
|
4861
|
+
if (command.json) {
|
|
4862
|
+
io.stdout(JSON.stringify(payload, null, 2));
|
|
4863
|
+
}
|
|
4864
|
+
else {
|
|
4865
|
+
io.stdout([
|
|
4866
|
+
`app_id: ${command.artifactId}`,
|
|
4867
|
+
'mode: guided_provisioning_plan',
|
|
4868
|
+
`dashboard: ${command.dashboardName}`,
|
|
4869
|
+
`proof: ${ANALYTICS_AGENT_GUIDANCE.dashboardCompletion.proofCommand}`,
|
|
4870
|
+
].join('\n'));
|
|
4871
|
+
}
|
|
4872
|
+
return 0;
|
|
4873
|
+
}
|
|
4651
4874
|
function parseAnalyticsChartsCreateArgs(args) {
|
|
4652
4875
|
if (args.includes('--help') || args.includes('-h')) {
|
|
4653
4876
|
return { command: 'help', topic: 'app analytics charts create' };
|
|
@@ -5526,7 +5749,7 @@ function parseTenderArgs(args) {
|
|
|
5526
5749
|
return parseContextRefreshArgs(resourceArgs.slice(3));
|
|
5527
5750
|
}
|
|
5528
5751
|
if (resourceArgs[1] === 'agent' && (resourceArgs[2] === undefined || resourceArgs[2] === '--help' || resourceArgs[2] === '-h')) {
|
|
5529
|
-
return { command: 'help', topic: 'app agent
|
|
5752
|
+
return { command: 'help', topic: 'app agent' };
|
|
5530
5753
|
}
|
|
5531
5754
|
if (resourceArgs[1] === 'agent' && resourceArgs[2] === 'heartbeat') {
|
|
5532
5755
|
return parseAgentHeartbeatArgs(resourceArgs.slice(3));
|
|
@@ -5576,6 +5799,9 @@ function parseTenderArgs(args) {
|
|
|
5576
5799
|
if (resourceArgs[1] === 'analytics' && resourceArgs[2] === 'dashboards') {
|
|
5577
5800
|
return parseAnalyticsDashboardsArgs(resourceArgs.slice(3));
|
|
5578
5801
|
}
|
|
5802
|
+
if (resourceArgs[1] === 'analytics' && resourceArgs[2] === 'provision') {
|
|
5803
|
+
return parseAnalyticsProvisionArgs(resourceArgs.slice(3));
|
|
5804
|
+
}
|
|
5579
5805
|
if (resourceArgs[1] === 'analytics' &&
|
|
5580
5806
|
resourceArgs[2] === 'properties' &&
|
|
5581
5807
|
(resourceArgs[3] === undefined || resourceArgs[3] === '--help' || resourceArgs[3] === '-h')) {
|
|
@@ -10150,6 +10376,9 @@ export async function runTenderCli(args, io = {
|
|
|
10150
10376
|
else if (command.topic === 'app preview watch') {
|
|
10151
10377
|
io.stdout(previewWatchHelp());
|
|
10152
10378
|
}
|
|
10379
|
+
else if (command.topic === 'app agent') {
|
|
10380
|
+
io.stdout(appAgentHelp());
|
|
10381
|
+
}
|
|
10153
10382
|
else if (command.topic === 'app agent heartbeat') {
|
|
10154
10383
|
io.stdout(agentHeartbeatHelp());
|
|
10155
10384
|
}
|
|
@@ -10189,6 +10418,9 @@ export async function runTenderCli(args, io = {
|
|
|
10189
10418
|
else if (command.topic === 'app analytics dashboards') {
|
|
10190
10419
|
io.stdout(analyticsDashboardsHelp());
|
|
10191
10420
|
}
|
|
10421
|
+
else if (command.topic === 'app analytics provision') {
|
|
10422
|
+
io.stdout(analyticsProvisionHelp());
|
|
10423
|
+
}
|
|
10192
10424
|
else if (command.topic === 'app analytics export') {
|
|
10193
10425
|
io.stdout(analyticsExportHelp());
|
|
10194
10426
|
}
|
|
@@ -10383,6 +10615,9 @@ export async function runTenderCli(args, io = {
|
|
|
10383
10615
|
if (command.command === 'app analytics dashboards') {
|
|
10384
10616
|
return await runAnalyticsDashboards(command, io, runtime);
|
|
10385
10617
|
}
|
|
10618
|
+
if (command.command === 'app analytics provision') {
|
|
10619
|
+
return runAnalyticsProvision(command, io);
|
|
10620
|
+
}
|
|
10386
10621
|
if (command.command === 'app analytics export catalog') {
|
|
10387
10622
|
return await runAnalyticsExportCatalog(command, io, runtime);
|
|
10388
10623
|
}
|