@assemble-dev/cli 0.0.1 → 0.2.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.
Files changed (3) hide show
  1. package/LICENSE +93 -0
  2. package/dist/index.js +160 -30
  3. package/package.json +17 -7
package/LICENSE ADDED
@@ -0,0 +1,93 @@
1
+ Elastic License 2.0
2
+
3
+ Copyright (c) 2026 Assemble (github.com/smundhra-git/assemble)
4
+
5
+ ## Acceptance
6
+
7
+ By using the software, you agree to all of the terms and conditions below.
8
+
9
+ ## Copyright License
10
+
11
+ The licensor grants you a non-exclusive, royalty-free, worldwide,
12
+ non-sublicensable, non-transferable license to use, copy, distribute, make
13
+ available, and prepare derivative works of the software, in each case subject
14
+ to the limitations and conditions below.
15
+
16
+ ## Limitations
17
+
18
+ You may not provide the software to third parties as a hosted or managed
19
+ service, where the service provides users with access to any substantial set of
20
+ the features or functionality of the software.
21
+
22
+ You may not move, change, disable, or circumvent the license key functionality
23
+ in the software, and you may not remove or obscure any functionality in the
24
+ software that is protected by the license key.
25
+
26
+ You may not alter, remove, or obscure any licensing, copyright, or other
27
+ notices of the licensor in the software. Any use of the licensor's trademarks
28
+ is subject to applicable law.
29
+
30
+ ## Patents
31
+
32
+ The licensor grants you a license, under any patent claims the licensor can
33
+ license, or becomes able to license, to make, have made, use, sell, offer for
34
+ sale, import and have imported the software, in each case subject to the
35
+ limitations and conditions in this license. This license does not cover any
36
+ patent claims that you cause to be infringed by modifications or additions to
37
+ the software. If you or your company make any written claim that the software
38
+ infringes or contributes to infringement of any patent, your patent license for
39
+ the software granted under these terms ends immediately. If your company makes
40
+ such a claim, your patent license ends immediately for work on behalf of your
41
+ company.
42
+
43
+ ## Notices
44
+
45
+ You must ensure that anyone who gets a copy of any part of the software from
46
+ you also gets a copy of these terms.
47
+
48
+ If you modify the software, you must include in any modified copies of the
49
+ software prominent notices stating that you have modified the software.
50
+
51
+ ## No Other Rights
52
+
53
+ These terms do not imply any licenses other than those expressly granted in
54
+ these terms.
55
+
56
+ ## Termination
57
+
58
+ If you use the software in violation of these terms, such use is not licensed,
59
+ and your licenses will automatically terminate. If the licensor provides you
60
+ with a notice of your violation, and you cease all violation of this license no
61
+ later than 30 days after you receive that notice, your licenses will be
62
+ reinstated retroactively. However, if you violate these terms after such
63
+ reinstatement, any additional violation of these terms will cause your licenses
64
+ to terminate automatically and permanently.
65
+
66
+ ## No Liability
67
+
68
+ *As far as the law allows, the software comes as is, without any warranty or
69
+ condition, and the licensor will not be liable to you for any damages arising
70
+ out of these terms or the use or nature of the software, under any kind of
71
+ legal claim.*
72
+
73
+ ## Definitions
74
+
75
+ The **licensor** is the entity offering these terms, and the **software** is
76
+ the software the licensor makes available under these terms, including any
77
+ portion of it.
78
+
79
+ **you** refers to the individual or entity agreeing to these terms.
80
+
81
+ **your company** is any legal entity, sole proprietorship, or other kind of
82
+ organization that you work for, plus all organizations that have control over,
83
+ are under the control of, or are under common control with that organization.
84
+ **control** means ownership of substantially all the assets of an entity, or
85
+ the power to direct its management and policies by vote, contract, or
86
+ otherwise. Control can be direct or indirect.
87
+
88
+ **your licenses** are all the licenses granted to you for the software under
89
+ these terms.
90
+
91
+ **use** means anything you do with the software requiring one of your licenses.
92
+
93
+ **trademark** means trademarks, service marks, and similar rights.
package/dist/index.js CHANGED
@@ -272,6 +272,72 @@ import {
272
272
  } from "@assemble-dev/sdk";
273
273
  import { generateRunId } from "@assemble-dev/shared-utils/ids";
274
274
 
275
+ // src/config/provider-api-key-flags.ts
276
+ import {
277
+ buildNamedApiKeyEnvVarName,
278
+ expectedProviderApiKeyNameFormat,
279
+ validateProviderApiKeyName
280
+ } from "@assemble-dev/shared-utils/provider-keys";
281
+ var anthropicApiKeyFlagDefinition = {
282
+ flagName: "anthropic-api-key",
283
+ baseEnvVarName: "ANTHROPIC_API_KEY"
284
+ };
285
+ var openaiApiKeyFlagDefinition = {
286
+ flagName: "openai-api-key",
287
+ baseEnvVarName: "OPENAI_API_KEY"
288
+ };
289
+ function parseProviderApiKeyFlags(input) {
290
+ const flagValuesByDefinition = [
291
+ [anthropicApiKeyFlagDefinition, input.anthropicApiKeyFlagValues],
292
+ [openaiApiKeyFlagDefinition, input.openaiApiKeyFlagValues]
293
+ ];
294
+ const assignments = [];
295
+ const seenEnvVarNames = /* @__PURE__ */ new Set();
296
+ for (const [definition, flagValues] of flagValuesByDefinition) {
297
+ for (const flagValue of flagValues) {
298
+ const result = parseSingleProviderApiKeyFlagValue(definition, flagValue);
299
+ if (typeof result === "string") {
300
+ return { outcome: "failed", message: result };
301
+ }
302
+ if (seenEnvVarNames.has(result.envVarName)) {
303
+ return {
304
+ outcome: "failed",
305
+ message: `Duplicate --${definition.flagName} value for ${result.envVarName}. Pass each key name at most once.`
306
+ };
307
+ }
308
+ seenEnvVarNames.add(result.envVarName);
309
+ assignments.push(result);
310
+ }
311
+ }
312
+ return { outcome: "parsed", assignments };
313
+ }
314
+ function applyProviderApiKeyAssignmentsToEnv(assignments, targetEnv) {
315
+ for (const assignment of assignments) {
316
+ targetEnv[assignment.envVarName] = assignment.apiKey;
317
+ }
318
+ }
319
+ function parseSingleProviderApiKeyFlagValue(definition, flagValue) {
320
+ const separatorIndex = flagValue.indexOf("=");
321
+ if (separatorIndex === -1) {
322
+ if (flagValue.length === 0) {
323
+ return `--${definition.flagName} requires a non-empty key value.`;
324
+ }
325
+ return { envVarName: definition.baseEnvVarName, apiKey: flagValue };
326
+ }
327
+ const keyName = flagValue.slice(0, separatorIndex);
328
+ const apiKey = flagValue.slice(separatorIndex + 1);
329
+ if (!validateProviderApiKeyName(keyName)) {
330
+ return `Invalid key name "${keyName}" in --${definition.flagName}. Expected ${expectedProviderApiKeyNameFormat}.`;
331
+ }
332
+ if (apiKey.length === 0) {
333
+ return `--${definition.flagName} ${keyName}= requires a non-empty key value.`;
334
+ }
335
+ return {
336
+ envVarName: buildNamedApiKeyEnvVarName(definition.baseEnvVarName, keyName),
337
+ apiKey
338
+ };
339
+ }
340
+
275
341
  // src/commands/run-wait-approval.ts
276
342
  import {
277
343
  buildHostedTraceUrl,
@@ -453,7 +519,7 @@ async function waitForApprovalDecisionAndResume(context) {
453
519
  }
454
520
 
455
521
  // src/commands/run.ts
456
- var runCommandUsage = "Usage: asm run <file> [--input <json>] [--input-file <path>] [--workflow <exportName>] [--trace-dir <dir>] [--no-upload] [--wait-approval [seconds]]";
522
+ var runCommandUsage = "Usage: asm run <file> [--input <json>] [--input-file <path>] [--workflow <exportName>] [--trace-dir <dir>] [--no-upload] [--wait-approval [seconds]] [--anthropic-api-key [name=]<key>] [--openai-api-key [name=]<key>]";
457
523
  var inputValidationMarker = "input failed schema validation:";
458
524
  function parseRunFlags(args) {
459
525
  const waitApprovalExtraction = extractWaitApprovalFlag(args);
@@ -468,7 +534,9 @@ function parseRunFlags(args) {
468
534
  "input-file": { type: "string" },
469
535
  workflow: { type: "string" },
470
536
  "trace-dir": { type: "string" },
471
- "no-upload": { type: "boolean" }
537
+ "no-upload": { type: "boolean" },
538
+ "anthropic-api-key": { type: "string", multiple: true },
539
+ "openai-api-key": { type: "string", multiple: true }
472
540
  },
473
541
  strict: true,
474
542
  allowPositionals: true
@@ -484,12 +552,26 @@ function parseRunFlags(args) {
484
552
  workflowExportName: values.workflow,
485
553
  traceDirectory: values["trace-dir"],
486
554
  noUpload: values["no-upload"] ?? false,
555
+ anthropicApiKeyFlagValues: values["anthropic-api-key"] ?? [],
556
+ openaiApiKeyFlagValues: values["openai-api-key"] ?? [],
487
557
  waitApprovalTimeoutSeconds: waitApprovalExtraction.waitApprovalTimeoutSeconds
488
558
  };
489
559
  } catch {
490
560
  return null;
491
561
  }
492
562
  }
563
+ function applyProviderApiKeyFlags(flags, output) {
564
+ const parseResult = parseProviderApiKeyFlags({
565
+ anthropicApiKeyFlagValues: flags.anthropicApiKeyFlagValues,
566
+ openaiApiKeyFlagValues: flags.openaiApiKeyFlagValues
567
+ });
568
+ if (parseResult.outcome === "failed") {
569
+ output.writeFailureLine(parseResult.message);
570
+ return false;
571
+ }
572
+ applyProviderApiKeyAssignmentsToEnv(parseResult.assignments, process.env);
573
+ return true;
574
+ }
493
575
  function buildWorkflowRunExecutionContext(runtime, output, flags, workflowDefinition, inputValue) {
494
576
  const runId = generateRunId();
495
577
  const traceDirectory = flags.traceDirectory ?? defaultTraceDirectory;
@@ -649,6 +731,9 @@ async function runRunCommand(args, runtime) {
649
731
  output.writeFailureLine(`Unrecognized run arguments. ${runCommandUsage}`);
650
732
  return 1;
651
733
  }
734
+ if (!applyProviderApiKeyFlags(flags, output)) {
735
+ return 1;
736
+ }
652
737
  const inputResult = resolveRunInputValue({
653
738
  inputJson: flags.inputJson,
654
739
  inputFilePath: flags.inputFilePath
@@ -677,7 +762,7 @@ async function runRunCommand(args, runtime) {
677
762
  }
678
763
 
679
764
  // src/commands/dev.ts
680
- var devCommandUsage = "Usage: asm dev <file> [--input <json>] [--input-file <path>] [--workflow <exportName>] [--trace-dir <dir>] [--watch-dir <dir>] [--no-upload]";
765
+ var devCommandUsage = "Usage: asm dev <file> [--input <json>] [--input-file <path>] [--workflow <exportName>] [--trace-dir <dir>] [--watch-dir <dir>] [--no-upload] [--anthropic-api-key [name=]<key>] [--openai-api-key [name=]<key>]";
681
766
  var defaultDebounceDelayMs = 150;
682
767
  function parseDevFlags(args) {
683
768
  try {
@@ -689,7 +774,9 @@ function parseDevFlags(args) {
689
774
  workflow: { type: "string" },
690
775
  "trace-dir": { type: "string" },
691
776
  "watch-dir": { type: "string" },
692
- "no-upload": { type: "boolean" }
777
+ "no-upload": { type: "boolean" },
778
+ "anthropic-api-key": { type: "string", multiple: true },
779
+ "openai-api-key": { type: "string", multiple: true }
693
780
  },
694
781
  strict: true,
695
782
  allowPositionals: true
@@ -705,7 +792,9 @@ function parseDevFlags(args) {
705
792
  workflowExportName: values.workflow,
706
793
  traceDirectory: values["trace-dir"],
707
794
  watchDirectory: values["watch-dir"],
708
- noUpload: values["no-upload"] ?? false
795
+ noUpload: values["no-upload"] ?? false,
796
+ anthropicApiKeyFlagValues: values["anthropic-api-key"] ?? [],
797
+ openaiApiKeyFlagValues: values["openai-api-key"] ?? []
709
798
  };
710
799
  } catch {
711
800
  return null;
@@ -778,6 +867,9 @@ async function runDevCommand(args, runtime, options = {}) {
778
867
  output.writeFailureLine(`Unrecognized dev arguments. ${devCommandUsage}`);
779
868
  return 1;
780
869
  }
870
+ if (!applyProviderApiKeyFlags(flags, output)) {
871
+ return 1;
872
+ }
781
873
  const inputResult = resolveRunInputValue({
782
874
  inputJson: flags.inputJson,
783
875
  inputFilePath: flags.inputFilePath
@@ -824,7 +916,13 @@ async function startDevWatchSession(runtime, output, flags, inputValue, options)
824
916
  import { tmpdir } from "os";
825
917
  import { join as join3 } from "path";
826
918
  import { parseArgs as parseArgs3 } from "util";
827
- import { runEvalSuite } from "@assemble-dev/evals";
919
+ import { z as z2 } from "zod";
920
+ import {
921
+ buildEvalWebhookPayload,
922
+ determineEvalSuiteStatus,
923
+ postEvalResultsToWebhook,
924
+ runEvalSuite
925
+ } from "@assemble-dev/evals";
828
926
  import { resolvePlatformConfig as resolvePlatformConfig2 } from "@assemble-dev/sdk";
829
927
 
830
928
  // src/commands/eval-metric-table.ts
@@ -978,7 +1076,7 @@ async function loadEvalSuiteFromFile(input) {
978
1076
  }
979
1077
 
980
1078
  // src/commands/eval.ts
981
- var evalCommandUsage = "Usage: asm eval <suite-file> [--suite <exportName>] [--results-dir <dir>] [--no-upload]";
1079
+ var evalCommandUsage = "Usage: asm eval <suite-file> [--suite <exportName>] [--results-dir <dir>] [--no-upload] [--webhook <url>]";
982
1080
  function parseEvalFlags(args) {
983
1081
  try {
984
1082
  const { values, positionals } = parseArgs3({
@@ -986,7 +1084,8 @@ function parseEvalFlags(args) {
986
1084
  options: {
987
1085
  suite: { type: "string" },
988
1086
  "results-dir": { type: "string" },
989
- "no-upload": { type: "boolean" }
1087
+ "no-upload": { type: "boolean" },
1088
+ webhook: { type: "string" }
990
1089
  },
991
1090
  strict: true,
992
1091
  allowPositionals: true
@@ -999,12 +1098,17 @@ function parseEvalFlags(args) {
999
1098
  filePath,
1000
1099
  suiteExportName: values.suite,
1001
1100
  resultsDirectory: values["results-dir"],
1002
- noUpload: values["no-upload"] ?? false
1101
+ noUpload: values["no-upload"] ?? false,
1102
+ webhookUrl: values.webhook
1003
1103
  };
1004
1104
  } catch {
1005
1105
  return null;
1006
1106
  }
1007
1107
  }
1108
+ var WebhookUrlSchema = z2.url({ protocol: /^https?$/ });
1109
+ function isValidWebhookUrl(webhookUrl) {
1110
+ return WebhookUrlSchema.safeParse(webhookUrl).success;
1111
+ }
1008
1112
  function buildEvalPlatformOptions(runtime, noUpload) {
1009
1113
  if (noUpload) {
1010
1114
  return {
@@ -1057,6 +1161,18 @@ function writeEvalResultLocationLines(runtime, result) {
1057
1161
  }
1058
1162
  runtime.writeLine("");
1059
1163
  }
1164
+ async function deliverEvalResultsToWebhook(runtime, output, webhookUrl, result) {
1165
+ const deliveryResult = await postEvalResultsToWebhook({
1166
+ webhookUrl,
1167
+ payload: buildEvalWebhookPayload(result),
1168
+ fetchImplementation: runtime.fetchImplementation
1169
+ });
1170
+ if (deliveryResult.outcome === "delivered") {
1171
+ runtime.writeLine(`Webhook delivered to ${webhookUrl}`);
1172
+ return;
1173
+ }
1174
+ output.writeFailureLine(`Webhook delivery failed: ${deliveryResult.message}`);
1175
+ }
1060
1176
  async function executeEvalSuiteRun(runtime, output, flags, suiteDefinition) {
1061
1177
  try {
1062
1178
  const result = await runEvalSuite({
@@ -1073,7 +1189,15 @@ async function executeEvalSuiteRun(runtime, output, flags, suiteDefinition) {
1073
1189
  })
1074
1190
  );
1075
1191
  writeEvalResultLocationLines(runtime, result);
1076
- return result.summary.failedCases > 0 ? 1 : 0;
1192
+ if (flags.webhookUrl !== void 0) {
1193
+ await deliverEvalResultsToWebhook(
1194
+ runtime,
1195
+ output,
1196
+ flags.webhookUrl,
1197
+ result
1198
+ );
1199
+ }
1200
+ return determineEvalSuiteStatus(result.summary) === "failed" ? 1 : 0;
1077
1201
  } catch (caughtError) {
1078
1202
  const reason = caughtError instanceof Error ? caughtError.message : String(caughtError);
1079
1203
  output.writeFailureLine(`Eval run failed: ${reason}`);
@@ -1087,6 +1211,12 @@ async function runEvalCommand(args, runtime) {
1087
1211
  output.writeFailureLine(`Unrecognized eval arguments. ${evalCommandUsage}`);
1088
1212
  return 1;
1089
1213
  }
1214
+ if (flags.webhookUrl !== void 0 && !isValidWebhookUrl(flags.webhookUrl)) {
1215
+ output.writeFailureLine(
1216
+ `Invalid --webhook url "${flags.webhookUrl}". Expected an http(s) URL.`
1217
+ );
1218
+ return 1;
1219
+ }
1090
1220
  const loadResult = await loadEvalSuiteFromFile({
1091
1221
  filePath: flags.filePath,
1092
1222
  exportName: flags.suiteExportName
@@ -1340,13 +1470,13 @@ import {
1340
1470
  writeFileSync as writeFileSync3
1341
1471
  } from "fs";
1342
1472
  import { dirname as dirname2, join as join5 } from "path";
1343
- import { z as z2 } from "zod";
1473
+ import { z as z3 } from "zod";
1344
1474
  var defaultCliBaseUrl = "https://api.assemble.dev";
1345
1475
  var cliDashboardKeysUrl = "https://app.assemble.dev/app/keys";
1346
- var CliConfigFileSchema = z2.object({
1347
- apiKey: z2.string().min(1).optional(),
1348
- baseUrl: z2.string().min(1).optional(),
1349
- workspaceId: z2.string().min(1).optional()
1476
+ var CliConfigFileSchema = z3.object({
1477
+ apiKey: z3.string().min(1).optional(),
1478
+ baseUrl: z3.string().min(1).optional(),
1479
+ workspaceId: z3.string().min(1).optional()
1350
1480
  });
1351
1481
  var configDirectoryMode = 448;
1352
1482
  var configFileMode = 384;
@@ -1389,11 +1519,11 @@ function writeCliConfigFile(homeDir, config) {
1389
1519
  }
1390
1520
 
1391
1521
  // src/config/cli-env.ts
1392
- import { z as z3 } from "zod";
1393
- var CliEnvSchema = z3.object({
1394
- ASSEMBLE_API_KEY: z3.string().min(1).optional(),
1395
- ASSEMBLE_BASE_URL: z3.string().min(1).optional(),
1396
- NO_COLOR: z3.string().optional()
1522
+ import { z as z4 } from "zod";
1523
+ var CliEnvSchema = z4.object({
1524
+ ASSEMBLE_API_KEY: z4.string().min(1).optional(),
1525
+ ASSEMBLE_BASE_URL: z4.string().min(1).optional(),
1526
+ NO_COLOR: z4.string().optional()
1397
1527
  });
1398
1528
  function parseCliEnvironment(environmentVariables) {
1399
1529
  const parsedEnvironment = CliEnvSchema.safeParse(environmentVariables);
@@ -1405,14 +1535,14 @@ function parseCliEnvironment(environmentVariables) {
1405
1535
 
1406
1536
  // src/platform/auth-check.ts
1407
1537
  import { AppErrorCode } from "@assemble-dev/shared-types";
1408
- import { z as z4 } from "zod";
1409
- var AuthCheckResponseSchema = z4.object({
1410
- workspaceId: z4.string().min(1)
1538
+ import { z as z5 } from "zod";
1539
+ var AuthCheckResponseSchema = z5.object({
1540
+ workspaceId: z5.string().min(1)
1411
1541
  });
1412
- var AuthCheckErrorResponseSchema = z4.object({
1413
- error: z4.object({
1414
- code: z4.enum(AppErrorCode),
1415
- message: z4.string()
1542
+ var AuthCheckErrorResponseSchema = z5.object({
1543
+ error: z5.object({
1544
+ code: z5.enum(AppErrorCode),
1545
+ message: z5.string()
1416
1546
  })
1417
1547
  });
1418
1548
  function resolveAuthCheckUrl(baseUrl) {
@@ -1581,7 +1711,7 @@ import {
1581
1711
  loadReplaySource,
1582
1712
  replayRun
1583
1713
  } from "@assemble-dev/sdk";
1584
- import { z as z5 } from "zod";
1714
+ import { z as z6 } from "zod";
1585
1715
 
1586
1716
  // src/commands/replay-comparison-format.ts
1587
1717
  var maxPrintedReplayDiffRows = 10;
@@ -1776,7 +1906,7 @@ async function loadReplayWorkflowFromFile(input) {
1776
1906
 
1777
1907
  // src/commands/replay.ts
1778
1908
  var replayCommandUsage = "Usage: asm replay [runId] --workflow-file <file> [--workflow <exportName>] [--from-step <n>] [--no-mock-tools] [--trace-dir <dir>] [--state-dir <dir>]";
1779
- var FromStepSchema = z5.coerce.number().int().min(0);
1909
+ var FromStepSchema = z6.coerce.number().int().min(0);
1780
1910
  function parseReplayFlags(args) {
1781
1911
  try {
1782
1912
  const { values, positionals } = parseArgs6({
@@ -2003,7 +2133,7 @@ var usageLines = [
2003
2133
  " (asm init [dir], --force to write into a non-empty directory)",
2004
2134
  " eval Run an eval suite file and print the metric table",
2005
2135
  " (asm eval <suite-file> [--suite <exportName>] [--results-dir <dir>]",
2006
- " [--no-upload])",
2136
+ " [--no-upload] [--webhook <url>])",
2007
2137
  " replay Re-run a recorded run and compare it to the original",
2008
2138
  " (asm replay [runId] --workflow-file <file> [--workflow <exportName>]",
2009
2139
  " [--from-step <n>] [--no-mock-tools] [--trace-dir <dir>] [--state-dir <dir>]",
package/package.json CHANGED
@@ -1,6 +1,16 @@
1
1
  {
2
2
  "name": "@assemble-dev/cli",
3
- "version": "0.0.1",
3
+ "version": "0.2.0",
4
+ "license": "Elastic-2.0",
5
+ "description": "Assemble command line interface for running agents and evals",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/smundhra-git/assemble.git",
9
+ "directory": "packages/cli"
10
+ },
11
+ "publishConfig": {
12
+ "access": "public"
13
+ },
4
14
  "type": "module",
5
15
  "bin": {
6
16
  "asm": "./dist/index.js"
@@ -11,10 +21,10 @@
11
21
  "dependencies": {
12
22
  "jiti": "^2.7.0",
13
23
  "zod": "^4.1.13",
14
- "@assemble-dev/evals": "0.0.0",
15
- "@assemble-dev/sdk": "0.0.1",
16
- "@assemble-dev/shared-utils": "0.0.0",
17
- "@assemble-dev/shared-types": "0.0.0"
24
+ "@assemble-dev/evals": "0.2.0",
25
+ "@assemble-dev/sdk": "0.2.0",
26
+ "@assemble-dev/shared-types": "0.2.0",
27
+ "@assemble-dev/shared-utils": "0.2.0"
18
28
  },
19
29
  "devDependencies": {
20
30
  "@types/node": "^20.19.0",
@@ -22,8 +32,8 @@
22
32
  "tsup": "^8.5.0",
23
33
  "typescript": "^5.8.3",
24
34
  "vitest": "^3.2.4",
25
- "@assemble-dev/providers": "0.0.0",
26
- "@assemble-dev/config": "0.0.0"
35
+ "@assemble-dev/config": "0.0.0",
36
+ "@assemble-dev/providers": "0.2.0"
27
37
  },
28
38
  "scripts": {
29
39
  "build": "tsup",