@tenderprompt/cli 0.1.31 → 0.1.33

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.
Files changed (3) hide show
  1. package/README.md +6 -4
  2. package/dist/index.js +221 -40
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -62,9 +62,9 @@ tender capabilities --json
62
62
  tender auth login --device --profile edit-preview --artifact artifact_123 --ttl 7d
63
63
  tender auth login --device --profile create --shopify-store tender-prompt --json
64
64
 
65
- tender app init artifact_123 --dir ./widget --preview --json
65
+ tender app init artifact_123 --dir ./product-survey-runtime --preview --json
66
66
 
67
- cd ./widget
67
+ cd ./product-survey-runtime
68
68
  npm run check
69
69
  git push tender main
70
70
 
@@ -141,12 +141,14 @@ tender --version
141
141
  tender capabilities --json
142
142
  tender app list --json
143
143
  tender app create --name "Exit Intent Widget" --json
144
- tender app create --name "Exit Intent Widget" --init --dir ./widget --preview --json
144
+ tender app create --name "Product Page Survey Runtime" --init --dir ./product-survey-runtime --preview --json
145
+ tender app create --name "Backend Widget" --init --dir ./widget --scaffold server-backed --preview --json
145
146
  tender app share create artifact_123 --expires 7d --claims 1 --json
146
147
  tender app share inspect tok_share_123 --json
147
148
  tender app claim tok_share_123 --dir ./widget --confirm source-and-setup --json
148
149
  tender app update artifact_123 --name "Sale Widget" --json
149
- tender app init artifact_123 --dir ./widget --preview --json
150
+ tender app init artifact_123 --dir ./product-survey-runtime --preview --json
151
+ tender app init artifact_123 --dir ./widget --scaffold server-backed --preview --json
150
152
  tender app bindings outbound --id shopify --host admin.shopify.com --dry-run --json
151
153
  tender app context status artifact_123 --dir ./widget --json
152
154
  tender app doctor --dir ./widget --json
package/dist/index.js CHANGED
@@ -89,6 +89,7 @@ const ANALYTICS_AGENT_GUIDANCE = {
89
89
  'clear split between shopper-facing UI and operator-facing analytics',
90
90
  ],
91
91
  };
92
+ const DEFAULT_TENDER_APP_SCAFFOLD_TEMPLATE = 'shopify-pdp-survey-runtime';
92
93
  class TenderCliUsageError extends Error {
93
94
  constructor(message) {
94
95
  super(message);
@@ -255,11 +256,13 @@ Examples:
255
256
  tender connectors bind SHOPIFY_CONNECTOR conn_123 --instance default --json
256
257
  tender app list --json
257
258
  tender app create --name "Exit Intent Widget" --json
258
- tender app create --name "Exit Intent Widget" --init --dir ./widget --preview --json
259
+ tender app create --name "Product Page Survey Runtime" --init --dir ./product-survey-runtime --preview --json
260
+ tender app create --name "Backend Widget" --init --dir ./widget --scaffold server-backed --preview --json
259
261
  tender app update artifact_123 --name "Sale Widget" --json
260
262
  tender app share create artifact_123 --expires 7d --claims 1 --json
261
263
  tender app claim tok_share_123 --dir ./widget --confirm source-and-setup --json
262
- tender app init artifact_123 --dir ./widget --preview --json
264
+ tender app init artifact_123 --dir ./product-survey-runtime --preview --json
265
+ tender app init artifact_123 --dir ./widget --scaffold server-backed --preview --json
263
266
  tender app validate artifact_123 --json
264
267
  tender app build artifact_123 --commit $(git rev-parse HEAD) --json
265
268
  tender app preview artifact_123 --commit $(git rev-parse HEAD) --stream --json
@@ -517,19 +520,22 @@ Examples:
517
520
  tender connectors shopify verify conn_123 --profile account --json`;
518
521
  }
519
522
  function connectorsShopifySourceInitHelp() {
520
- return `Usage: tender connectors shopify source init <connector-id> --dir <path> --client-id <shopify-client-id> [--source-name <name>] [--scopes <csv>] [--force] [--base-url <url>] [--token <token>] [--profile <name>] [--json]
523
+ return `Usage: tender connectors shopify source init <connector-id> --dir <path> --client-id <shopify-client-id> [--template <minimal|shopify-pdp-survey>] [--source-name <name>] [--scopes <csv>] [--force] [--base-url <url>] [--token <token>] [--profile <name>] [--json]
521
524
 
522
525
  Creates or reuses an internal Tender source artifact for the merchant-owned
523
- Shopify app, checks it out to --dir, writes a minimal non-secret Shopify app
524
- source tree, commits it, pushes it to Artifact Git, and records
526
+ Shopify app, checks it out to --dir, writes a product page survey app block
527
+ source tree by default, commits it, pushes it to Artifact Git, and records
525
528
  sourceArtifactId on the connector.
526
529
 
527
- The CLI bootstraps and deploys source. App blocks, web pixels, customer
528
- metadata definitions, and app-owned GraphQL resources are source edits guided by
529
- playbooks, not source init flags.
530
+ Pass --template minimal for an empty non-secret Shopify app source tree.
531
+
532
+ The CLI bootstraps source. Additional app blocks, web pixels, customer metadata
533
+ definitions, and app-owned GraphQL resources are source edits guided by
534
+ playbooks.
530
535
 
531
536
  Examples:
532
- tender connectors shopify source init conn_123 --dir ./shopify-app --client-id abc --profile account --json`;
537
+ tender connectors shopify source init conn_123 --dir ./shopify-app --client-id abc --profile account --json
538
+ tender connectors shopify source init conn_123 --dir ./shopify-app --client-id abc --template minimal --profile account --json`;
533
539
  }
534
540
  function connectorsShopifySourceCheckoutHelp() {
535
541
  return `Usage: tender connectors shopify source checkout <connector-id> --dir <path> [--remote <name>] [--base-url <url>] [--token <token>] [--profile <name>] [--json]
@@ -558,6 +564,11 @@ SHOPIFY_APP_AUTOMATION_TOKEN is not set locally, the CLI requests the
558
564
  connector's stored App Automation Token and injects it only into the spawned
559
565
  Shopify CLI child process.
560
566
 
567
+ For interactive agent work where Shopify CLI is already logged in, run the
568
+ printed npx --yes @shopify/cli@latest app deploy command directly instead of
569
+ --confirm deploy. That uses the local Shopify CLI session and bypasses Tender
570
+ deploy-token handoff.
571
+
561
572
  Examples:
562
573
  tender connectors shopify source deploy conn_123 --dir ./shopify-app --version connector-source-smoke --confirm deploy --profile account --json`;
563
574
  }
@@ -676,12 +687,14 @@ Commands:
676
687
  Examples:
677
688
  tender app list --json
678
689
  tender app create --name "Exit Intent Widget" --json
679
- tender app create --name "Exit Intent Widget" --init --dir ./widget --preview --json
690
+ tender app create --name "Product Page Survey Runtime" --init --dir ./product-survey-runtime --preview --json
691
+ tender app create --name "Backend Widget" --init --dir ./widget --scaffold server-backed --preview --json
680
692
  tender app update artifact_123 --name "Sale Widget" --json
681
693
  tender app share create artifact_123 --expires 7d --claims 1 --json
682
694
  tender app share inspect tok_share_123 --json
683
695
  tender app claim tok_share_123 --dir ./widget --confirm source-and-setup --json
684
- tender app init artifact_123 --dir ./widget --preview --json
696
+ tender app init artifact_123 --dir ./product-survey-runtime --preview --json
697
+ tender app init artifact_123 --dir ./widget --scaffold server-backed --preview --json
685
698
  tender app validate artifact_123 --json
686
699
  tender app build artifact_123 --commit $(git rev-parse HEAD) --json
687
700
  tender app preview artifact_123 --commit $(git rev-parse HEAD) --stream --json
@@ -1105,13 +1118,13 @@ Examples:
1105
1118
  TENDER_API_TOKEN=tpat_... tender app list --base-url https://app.tenderprompt.com --json`;
1106
1119
  }
1107
1120
  function artifactsCreateHelp() {
1108
- return `Usage: tender app create --name <name> [--init] [--dir <path>] [--scaffold <server-backed|none>] [--preview] [--target-pack <id>] [--target-pack-version <version>] [--base-url <url>] [--token <token>] [--profile <name>] [--json]
1121
+ return `Usage: tender app create --name <name> [--init] [--dir <path>] [--scaffold <server-backed|shopify-pdp-survey-runtime|none>] [--preview] [--target-pack <id>] [--target-pack-version <version>] [--base-url <url>] [--token <token>] [--profile <name>] [--json]
1109
1122
 
1110
1123
  Options:
1111
1124
  --name <name> App name.
1112
1125
  --init Initialize a local checkout after creating the app.
1113
1126
  --dir <path> Local checkout directory for --init. Defaults to current directory.
1114
- --scaffold <value> API-derived scaffold for empty app source: server-backed or none. Defaults to server-backed.
1127
+ --scaffold <value> API-derived scaffold for empty app source: server-backed, shopify-pdp-survey-runtime, or none. Defaults to shopify-pdp-survey-runtime.
1115
1128
  --no-scaffold Alias for --scaffold none.
1116
1129
  --preview After --init writes and pushes initial source, request a preview build.
1117
1130
  --remote <name> Git remote name for --init. Defaults to tender.
@@ -1126,7 +1139,8 @@ Options:
1126
1139
 
1127
1140
  Examples:
1128
1141
  tender app create --name "Exit Intent Widget" --json
1129
- tender app create --name "Exit Intent Widget" --init --dir ./widget --preview --json
1142
+ tender app create --name "Product Page Survey Runtime" --init --dir ./product-survey-runtime --preview --json
1143
+ tender app create --name "Backend Widget" --init --dir ./widget --scaffold server-backed --preview --json
1130
1144
  tender app create --name "Exit Intent Widget" --profile account --json`;
1131
1145
  }
1132
1146
  function artifactsUpdateHelp() {
@@ -1143,12 +1157,12 @@ Examples:
1143
1157
  tender app update artifact_123 --name "Sale Widget" --json`;
1144
1158
  }
1145
1159
  function artifactsInitHelp() {
1146
- return `Usage: tender app init <app-id> [--dir <path>] [--remote <name>] [--scaffold <server-backed|none>] [--preview] [--base-url <url>] [--token <token>] [--profile <name>] [--ttl <7d|14d|30d>] [--dry-run] [--force] [--json]
1160
+ return `Usage: tender app init <app-id> [--dir <path>] [--remote <name>] [--scaffold <server-backed|shopify-pdp-survey-runtime|none>] [--preview] [--base-url <url>] [--token <token>] [--profile <name>] [--ttl <7d|14d|30d>] [--dry-run] [--force] [--json]
1147
1161
 
1148
1162
  Options:
1149
1163
  --dir <path> Local checkout directory to create/update. Defaults to current directory.
1150
1164
  --remote <name> Git remote name to add or update. Defaults to tender.
1151
- --scaffold <value> API-derived scaffold for empty app source: server-backed or none. Defaults to server-backed.
1165
+ --scaffold <value> API-derived scaffold for empty app source: server-backed, shopify-pdp-survey-runtime, or none. Defaults to shopify-pdp-survey-runtime.
1152
1166
  --no-scaffold Alias for --scaffold none.
1153
1167
  --preview Request a preview build for the initialized source commit.
1154
1168
  --base-url <url> Tender base URL. Defaults to TENDER_BASE_URL, saved profile base URL, or https://app.tenderprompt.com.
@@ -1161,8 +1175,8 @@ Options:
1161
1175
 
1162
1176
  Examples:
1163
1177
  tender app init artifact_123 --dir ./widget --dry-run --json
1164
- tender app init artifact_123 --dir ./widget --json
1165
- tender app init artifact_123 --dir ./widget --preview --json
1178
+ tender app init artifact_123 --dir ./product-survey-runtime --preview --json
1179
+ tender app init artifact_123 --dir ./widget --scaffold server-backed --json
1166
1180
  tender app init artifact_123 --dir ./widget --force --json`;
1167
1181
  }
1168
1182
  function artifactsContextFetchHelp() {
@@ -1494,7 +1508,7 @@ function tenderCliCapabilities() {
1494
1508
  cli: {
1495
1509
  name: CLI_PACKAGE_NAME,
1496
1510
  version: CLI_PACKAGE_VERSION,
1497
- latestRunner: 'npm exec --yes @tenderprompt/cli@latest --',
1511
+ latestRunner: 'npm exec --yes --package @tenderprompt/cli@latest -- tender',
1498
1512
  },
1499
1513
  recommendedSkill: RECOMMENDED_TENDER_PROMPT_SKILL,
1500
1514
  playbooks: {
@@ -1560,7 +1574,7 @@ function tenderCliCapabilities() {
1560
1574
  },
1561
1575
  description: 'Agent-safe Tender App source, lifecycle, analytics, and local scaffold controls.',
1562
1576
  discovery: {
1563
- primary: 'npm exec --yes @tenderprompt/cli@latest -- capabilities --json',
1577
+ primary: 'npm exec --yes --package @tenderprompt/cli@latest -- tender capabilities --json',
1564
1578
  layeredHelp: [
1565
1579
  'tender --version',
1566
1580
  'tender --help',
@@ -1623,10 +1637,14 @@ function tenderCliCapabilities() {
1623
1637
  },
1624
1638
  {
1625
1639
  name: 'create_new_app_with_preview',
1626
- when: 'When the user wants a new Tender App that is immediately visible.',
1627
- commands: ['tender app create --name <name> --init --dir <dir> --preview --json'],
1640
+ when: 'When the user wants a new Shopify-first Tender App that is immediately visible.',
1641
+ commands: [
1642
+ 'tender app create --name "Product Page Survey Runtime" --init --dir ./product-survey-runtime --preview --json',
1643
+ 'tender app create --name <name> --init --dir <dir> --scaffold server-backed --preview --json',
1644
+ ],
1628
1645
  notes: [
1629
- 'create --init uses the API-derived scaffold when the new app has no source.',
1646
+ 'create --init defaults to the Shopify product page survey runtime scaffold when the new app has no source.',
1647
+ 'Pass --scaffold server-backed only when the first app is a generic backend app instead of the Shopify survey starter.',
1630
1648
  '--preview requests a preview build for the initial source commit after the push.',
1631
1649
  ],
1632
1650
  },
@@ -1789,7 +1807,7 @@ function tenderCliCapabilities() {
1789
1807
  },
1790
1808
  {
1791
1809
  command: 'tender app create --name <name> --init --dir <dir> --preview --json',
1792
- purpose: 'Create a new Tender App, initialize API-derived source in a local checkout, push it, and request a preview build.',
1810
+ purpose: 'Create a new Tender App, initialize the default Shopify product page survey runtime source in a local checkout, push it, and request a preview build.',
1793
1811
  requiresAuth: true,
1794
1812
  writes: true,
1795
1813
  dryRun: false,
@@ -2233,8 +2251,8 @@ function parseTtl(value) {
2233
2251
  return value;
2234
2252
  }
2235
2253
  function parseScaffoldTemplate(value) {
2236
- if (value !== 'server-backed' && value !== 'none') {
2237
- throw new TenderCliUsageError('--scaffold must be one of server-backed or none.');
2254
+ if (value !== 'server-backed' && value !== 'shopify-pdp-survey-runtime' && value !== 'none') {
2255
+ throw new TenderCliUsageError('--scaffold must be one of server-backed, shopify-pdp-survey-runtime, or none.');
2238
2256
  }
2239
2257
  return value;
2240
2258
  }
@@ -3198,7 +3216,8 @@ function parseArtifactsCreateArgs(args) {
3198
3216
  let remoteName = 'tender';
3199
3217
  let ttl = '7d';
3200
3218
  let force = false;
3201
- let scaffold = 'server-backed';
3219
+ let scaffold = DEFAULT_TENDER_APP_SCAFFOLD_TEMPLATE;
3220
+ let scaffoldSpecified = false;
3202
3221
  let preview = false;
3203
3222
  let baseUrl = null;
3204
3223
  let flagToken = null;
@@ -3224,6 +3243,7 @@ function parseArtifactsCreateArgs(args) {
3224
3243
  }
3225
3244
  if (arg === '--no-scaffold') {
3226
3245
  scaffold = 'none';
3246
+ scaffoldSpecified = true;
3227
3247
  continue;
3228
3248
  }
3229
3249
  if (arg === '--name') {
@@ -3274,6 +3294,7 @@ function parseArtifactsCreateArgs(args) {
3274
3294
  }
3275
3295
  if (arg === '--scaffold') {
3276
3296
  scaffold = parseScaffoldTemplate(args[index + 1]);
3297
+ scaffoldSpecified = true;
3277
3298
  index += 1;
3278
3299
  continue;
3279
3300
  }
@@ -3299,7 +3320,7 @@ function parseArtifactsCreateArgs(args) {
3299
3320
  }
3300
3321
  if (!init) {
3301
3322
  if (preview) {
3302
- throw new TenderCliUsageError('--preview requires --init. Example: tender app create --name "Exit Intent Widget" --init --dir ./widget --preview --json');
3323
+ throw new TenderCliUsageError('--preview requires --init. Example: tender app create --name "Product Page Survey Runtime" --init --dir ./product-survey-runtime --preview --json');
3303
3324
  }
3304
3325
  if (force) {
3305
3326
  throw new TenderCliUsageError('--force is only valid with --init.');
@@ -3313,7 +3334,7 @@ function parseArtifactsCreateArgs(args) {
3313
3334
  if (ttl !== '7d') {
3314
3335
  throw new TenderCliUsageError('--ttl is only valid with --init.');
3315
3336
  }
3316
- if (scaffold !== 'server-backed') {
3337
+ if (scaffoldSpecified) {
3317
3338
  throw new TenderCliUsageError('--scaffold is only valid with --init.');
3318
3339
  }
3319
3340
  }
@@ -3684,6 +3705,7 @@ function parseConnectorsShopifySourceInitArgs(args) {
3684
3705
  let clientId = null;
3685
3706
  let sourceName = null;
3686
3707
  let scopes = null;
3708
+ let template = DEFAULT_SHOPIFY_CONNECTOR_SOURCE_TEMPLATE;
3687
3709
  let force = false;
3688
3710
  for (let index = 0; index < parsed.remaining.length; index += 1) {
3689
3711
  const arg = parsed.remaining[index];
@@ -3707,6 +3729,11 @@ function parseConnectorsShopifySourceInitArgs(args) {
3707
3729
  index += 1;
3708
3730
  continue;
3709
3731
  }
3732
+ if (arg === '--template') {
3733
+ template = parseShopifyConnectorSourceTemplate(parsed.remaining[index + 1]);
3734
+ index += 1;
3735
+ continue;
3736
+ }
3710
3737
  if (arg === '--force') {
3711
3738
  force = true;
3712
3739
  continue;
@@ -3726,6 +3753,7 @@ function parseConnectorsShopifySourceInitArgs(args) {
3726
3753
  clientId,
3727
3754
  sourceName,
3728
3755
  scopes,
3756
+ template,
3729
3757
  force,
3730
3758
  ...parsed,
3731
3759
  };
@@ -3991,7 +4019,7 @@ function parseArtifactsInitArgs(args) {
3991
4019
  let flagToken = null;
3992
4020
  let profileName = null;
3993
4021
  let ttl = '7d';
3994
- let scaffold = 'server-backed';
4022
+ let scaffold = DEFAULT_TENDER_APP_SCAFFOLD_TEMPLATE;
3995
4023
  let preview = false;
3996
4024
  let dryRun = false;
3997
4025
  let force = false;
@@ -8048,6 +8076,11 @@ function readObjectString(value, key) {
8048
8076
  const field = record?.[key];
8049
8077
  return typeof field === 'string' && field.trim() ? field : null;
8050
8078
  }
8079
+ function readObjectArray(value, key) {
8080
+ const record = readObject(value);
8081
+ const field = record?.[key];
8082
+ return Array.isArray(field) ? field : [];
8083
+ }
8051
8084
  function readPreviewUrlFromJob(job) {
8052
8085
  return readObjectString(job?.result, 'previewUrl');
8053
8086
  }
@@ -8072,8 +8105,22 @@ function readReleaseGitRefFromResult(result) {
8072
8105
  function formatPublishResultLines(result) {
8073
8106
  const record = readObject(result);
8074
8107
  const releaseGitRef = readReleaseGitRefFromResult(result);
8108
+ const publishedAssets = readObjectArray(record, 'publishedAssets');
8109
+ const pinnedClientAsset = publishedAssets
8110
+ .map((asset) => readObject(asset))
8111
+ .find((asset) => asset?.sourcePath === 'client.js' && readObjectString(asset, 'pinnedUrl')) ??
8112
+ publishedAssets
8113
+ .map((asset) => readObject(asset))
8114
+ .find((asset) => asset?.assetPath === 'client.js' && readObjectString(asset, 'pinnedUrl'));
8115
+ const integrationSnippets = readObject(record?.integrationSnippets);
8116
+ const pinnedClientUrl = readObjectString(pinnedClientAsset, 'pinnedUrl');
8117
+ const pinnedModuleScript = readObjectString(integrationSnippets, 'moduleScript');
8075
8118
  return [
8076
8119
  ...(readObjectString(record, 'publishedUrl') ? [`published_url: ${readObjectString(record, 'publishedUrl')}`] : []),
8120
+ ...(readObjectString(record, 'versionUrl') ? [`version_url: ${readObjectString(record, 'versionUrl')}`] : []),
8121
+ ...(readObjectString(record, 'releaseId') ? [`release_id: ${readObjectString(record, 'releaseId')}`] : []),
8122
+ ...(pinnedClientUrl ? [`pinned_client_asset: ${pinnedClientUrl}`] : []),
8123
+ ...(pinnedModuleScript ? [`pinned_module_script: ${pinnedModuleScript}`] : []),
8077
8124
  ...(releaseGitRef?.tagName ? [`release_tag: ${releaseGitRef.tagName}`] : []),
8078
8125
  ...(releaseGitRef?.commitSha ? [`source_commit: ${releaseGitRef.commitSha}`] : []),
8079
8126
  ];
@@ -11258,6 +11305,13 @@ function uniqueSortedScopes(scopes) {
11258
11305
  function parseScopeCsv(value) {
11259
11306
  return uniqueSortedScopes((value ?? '').split(/[,\s]+/));
11260
11307
  }
11308
+ const DEFAULT_SHOPIFY_CONNECTOR_SOURCE_TEMPLATE = 'shopify-pdp-survey';
11309
+ function parseShopifyConnectorSourceTemplate(value) {
11310
+ if (value === 'minimal' || value === 'shopify-pdp-survey') {
11311
+ return value;
11312
+ }
11313
+ throw new TenderCliUsageError('--template must be one of minimal or shopify-pdp-survey.');
11314
+ }
11261
11315
  function defaultShopifySourceScopes(connectorScopes, override) {
11262
11316
  if (override) {
11263
11317
  return parseScopeCsv(override);
@@ -11265,6 +11319,107 @@ function defaultShopifySourceScopes(connectorScopes, override) {
11265
11319
  const fromConnector = Array.isArray(connectorScopes) ? connectorScopes.filter((scope) => typeof scope === 'string') : [];
11266
11320
  return uniqueSortedScopes(fromConnector);
11267
11321
  }
11322
+ function buildShopifyPdpSurveySourceTemplateFiles() {
11323
+ const placeholderClientUrl = 'https://example.invalid/tender-product-survey/release-placeholder/client.js';
11324
+ const placeholderStylesUrl = 'https://example.invalid/tender-product-survey/release-placeholder/styles.css';
11325
+ const extensionToml = `name = "Tender product survey"
11326
+ type = "theme"
11327
+ `;
11328
+ const blockLiquid = `{% liquid
11329
+ assign selected_version = block.settings.widget_version | default: 'production'
11330
+ case selected_version
11331
+ when 'release-placeholder'
11332
+ assign runtime_src = '${placeholderClientUrl}'
11333
+ assign stylesheet_src = '${placeholderStylesUrl}'
11334
+ else
11335
+ assign runtime_src = '${placeholderClientUrl}'
11336
+ assign stylesheet_src = '${placeholderStylesUrl}'
11337
+ endcase
11338
+ %}
11339
+
11340
+ <div
11341
+ {{ block.shopify_attributes }}
11342
+ data-tender-product-survey-block
11343
+ data-widget-version="{{ selected_version | escape }}"
11344
+ >
11345
+ <link rel="preload" href="{{ stylesheet_src | escape }}" as="style">
11346
+ <link rel="stylesheet" href="{{ stylesheet_src | escape }}">
11347
+ <script type="module" src="{{ runtime_src | escape }}"></script>
11348
+ <tender-product-survey
11349
+ data-question="{{ block.settings.question | escape }}"
11350
+ data-helper="{{ block.settings.helper_text | escape }}"
11351
+ data-options="{{ block.settings.options | escape }}"
11352
+ data-property-name="_tender_survey_source"
11353
+ data-product-id="{{ product.id }}"
11354
+ data-product-handle="{{ product.handle | escape }}"
11355
+ ></tender-product-survey>
11356
+ </div>
11357
+
11358
+ {% schema %}
11359
+ {
11360
+ "name": "Product survey",
11361
+ "target": "section",
11362
+ "settings": [
11363
+ {
11364
+ "type": "select",
11365
+ "id": "widget_version",
11366
+ "label": "Runtime version",
11367
+ "default": "production",
11368
+ "options": [
11369
+ {
11370
+ "value": "production",
11371
+ "label": "Production pinned release"
11372
+ },
11373
+ {
11374
+ "value": "release-placeholder",
11375
+ "label": "Pinned release placeholder"
11376
+ }
11377
+ ]
11378
+ },
11379
+ {
11380
+ "type": "text",
11381
+ "id": "question",
11382
+ "label": "Question",
11383
+ "default": "How did you hear about this product?"
11384
+ },
11385
+ {
11386
+ "type": "text",
11387
+ "id": "helper_text",
11388
+ "label": "Helper text",
11389
+ "default": "Choose one answer and we will save it with your cart."
11390
+ },
11391
+ {
11392
+ "type": "text",
11393
+ "id": "options",
11394
+ "label": "Options",
11395
+ "default": "Instagram|friend|search|other"
11396
+ }
11397
+ ]
11398
+ }
11399
+ {% endschema %}
11400
+ `;
11401
+ const readme = `# Tender Product Survey App Block
11402
+
11403
+ This theme app extension contains a thin product page app block for the Tender
11404
+ product survey runtime.
11405
+
11406
+ ## Runtime Release Pinning
11407
+
11408
+ Replace the placeholder URLs in \`blocks/product_survey.liquid\` after the
11409
+ runtime is published. Use the exact pinned \`client.js\` and \`styles.css\` URLs
11410
+ from the publish JSON. Keep \`production\` plus recent pinned releases in the
11411
+ \`widget_version\` setting so merchants can switch versions in the theme editor.
11412
+
11413
+ Do not point this block to \`latest\`, and do not expose raw runtime URLs as
11414
+ merchant-editable settings.
11415
+ `;
11416
+ return new Map([
11417
+ ['extensions/tender-product-survey/README.md', readme],
11418
+ ['extensions/tender-product-survey/package.json', '{\n "name": "tender-product-survey",\n "private": true,\n "version": "0.0.0"\n}\n'],
11419
+ ['extensions/tender-product-survey/shopify.extension.toml', extensionToml],
11420
+ ['extensions/tender-product-survey/blocks/product_survey.liquid', blockLiquid],
11421
+ ]);
11422
+ }
11268
11423
  function buildShopifySourceFiles(input) {
11269
11424
  const appName = requireShopifySourceString(input.connector.appName, 'Tender Prompt Apps');
11270
11425
  const adminApiVersion = requireShopifySourceString(input.connector.adminApiVersion, '2026-04');
@@ -11279,6 +11434,7 @@ function buildShopifySourceFiles(input) {
11279
11434
  adminApiVersion,
11280
11435
  clientId: input.clientId,
11281
11436
  scopes,
11437
+ sourceTemplate: input.template,
11282
11438
  secrets: {
11283
11439
  clientSecret: 'stored in Tender connector credentials, not in this source tree',
11284
11440
  appAutomationToken: 'stored in Tender connector secret store, not in this source tree',
@@ -11304,6 +11460,24 @@ api_version = ${tomlString(adminApiVersion)}
11304
11460
  [build]
11305
11461
  automatically_update_urls_on_dev = true
11306
11462
  `;
11463
+ const templateFileSummary = input.template === 'shopify-pdp-survey'
11464
+ ? '- `extensions/tender-product-survey/`: A thin product page app block that loads a pinned Tender runtime release.\n'
11465
+ : '';
11466
+ const addCapabilities = input.template === 'shopify-pdp-survey'
11467
+ ? 'This bootstrap includes the first product page survey app block only. Add other app blocks, web pixels, customer metadata definitions, or app-owned GraphQL resources as separate source edits guided by Shopify connector playbooks.'
11468
+ : 'This bootstrap intentionally does not generate app blocks, web pixels, customer metadata definitions, or app-owned GraphQL resources. Add those as source edits using the Shopify connector playbooks so the source tree stays the durable record of what the merchant-owned app actually contains.';
11469
+ const runtimeReleasePinning = input.template === 'shopify-pdp-survey'
11470
+ ? `## Runtime Release Pin
11471
+
11472
+ The product survey block must load a pinned Tender runtime release. After
11473
+ publishing the survey runtime, replace the placeholder URLs in
11474
+ \`extensions/tender-product-survey/blocks/product_survey.liquid\` with the exact
11475
+ pinned URLs returned by the publish JSON. Keep \`production\` plus recent pinned
11476
+ releases in the \`widget_version\` setting so the merchant can switch versions in
11477
+ the theme editor. Do not point the block at a \`latest\` URL.
11478
+
11479
+ `
11480
+ : '';
11307
11481
  const readme = `# ${appName}
11308
11482
 
11309
11483
  This is the merchant-owned Shopify app source bootstrapped by Tender Prompt for
@@ -11314,13 +11488,13 @@ connector \`${input.connectorId}\`.
11314
11488
  - \`shopify.app.toml\`: Shopify app configuration and reviewed Admin API scopes.
11315
11489
  - \`connector.json\`: Non-secret Tender metadata that maps this source tree back
11316
11490
  to the connector.
11491
+ ${templateFileSummary}
11317
11492
 
11318
11493
  ## Add capabilities
11319
11494
 
11320
- This bootstrap intentionally does not generate app blocks, web pixels, customer
11321
- metadata definitions, or app-owned GraphQL resources. Add those as source edits
11322
- using the Shopify connector playbooks so the source tree stays the durable
11323
- record of what the merchant-owned app actually contains.
11495
+ ${addCapabilities}
11496
+
11497
+ ${runtimeReleasePinning}
11324
11498
 
11325
11499
  ## Secrets
11326
11500
 
@@ -11341,14 +11515,20 @@ npx --yes @shopify/cli@latest app config validate --path . --json
11341
11515
  tender connectors shopify source deploy ${input.connectorId} --dir . --confirm deploy --profile account --json
11342
11516
  \`\`\`
11343
11517
  `;
11518
+ const files = new Map([
11519
+ ['.gitignore', '.shopify/\nnode_modules/\n.env\n.env.*\n'],
11520
+ ['README.md', readme],
11521
+ ['connector.json', `${JSON.stringify(connectorManifest, null, 2)}\n`],
11522
+ ['shopify.app.toml', shopifyAppToml],
11523
+ ]);
11524
+ if (input.template === 'shopify-pdp-survey') {
11525
+ for (const [relativePath, content] of buildShopifyPdpSurveySourceTemplateFiles()) {
11526
+ files.set(relativePath, content);
11527
+ }
11528
+ }
11344
11529
  return {
11345
11530
  manifest: connectorManifest,
11346
- files: new Map([
11347
- ['.gitignore', '.shopify/\nnode_modules/\n.env\n.env.*\n'],
11348
- ['README.md', readme],
11349
- ['connector.json', `${JSON.stringify(connectorManifest, null, 2)}\n`],
11350
- ['shopify.app.toml', shopifyAppToml],
11351
- ]),
11531
+ files,
11352
11532
  };
11353
11533
  }
11354
11534
  async function fileExists(filePath) {
@@ -11741,6 +11921,7 @@ async function runConnectorsShopifySourceInit(command, io, runtime) {
11741
11921
  connector,
11742
11922
  clientId: command.clientId,
11743
11923
  scopes: command.scopes,
11924
+ template: command.template,
11744
11925
  });
11745
11926
  const files = await writeShopifySourceFiles({ dir, files: source.files, force: command.force });
11746
11927
  const gitCommit = await commitAndPushSourceFiles({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tenderprompt/cli",
3
- "version": "0.1.31",
3
+ "version": "0.1.33",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "tender": "bin/tender.js"