@sweny-ai/core 0.1.54 → 0.1.55

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 (41) hide show
  1. package/dist/__tests__/executor.test.js +2 -1
  2. package/dist/__tests__/integration/sources.integration.test.d.ts +1 -0
  3. package/dist/__tests__/integration/sources.integration.test.js +123 -0
  4. package/dist/__tests__/workflow-yaml.test.js +12 -5
  5. package/dist/cli/__tests__/report-cloud.test.d.ts +1 -0
  6. package/dist/cli/__tests__/report-cloud.test.js +165 -0
  7. package/dist/cli/cloud-report.d.ts +12 -0
  8. package/dist/cli/cloud-report.js +79 -0
  9. package/dist/cli/config-file.d.ts +3 -3
  10. package/dist/cli/config-file.js +18 -0
  11. package/dist/cli/config.d.ts +3 -0
  12. package/dist/cli/config.js +18 -2
  13. package/dist/cli/config.test.js +65 -1
  14. package/dist/cli/e2e.js +4 -2
  15. package/dist/cli/e2e.test.js +9 -2
  16. package/dist/cli/main.js +48 -3
  17. package/dist/cli/output.test.js +1 -0
  18. package/dist/cli/publish.test.d.ts +1 -0
  19. package/dist/cli/publish.test.js +610 -0
  20. package/dist/executor.d.ts +8 -0
  21. package/dist/executor.js +21 -3
  22. package/dist/executor.test.js +56 -1
  23. package/dist/index.d.ts +2 -2
  24. package/dist/index.js +1 -1
  25. package/dist/mermaid.test.js +2 -0
  26. package/dist/schema.d.ts +174 -46
  27. package/dist/schema.js +31 -2
  28. package/dist/sources.d.ts +70 -0
  29. package/dist/sources.js +194 -0
  30. package/dist/sources.test.d.ts +1 -0
  31. package/dist/sources.test.js +264 -0
  32. package/dist/sources.validation.test.d.ts +12 -0
  33. package/dist/sources.validation.test.js +360 -0
  34. package/dist/templates.d.ts +6 -2
  35. package/dist/templates.js +36 -46
  36. package/dist/testing.js +4 -1
  37. package/dist/types.d.ts +8 -1
  38. package/dist/types.js +0 -5
  39. package/dist/workflows/browser.js +1 -1
  40. package/dist/workflows/triage.yml +1 -23
  41. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  import { describe, it, expect } from "vitest";
2
- import { validateInputs } from "./config.js";
2
+ import { validateInputs, parseCliInputs } from "./config.js";
3
3
  /**
4
4
  * Focused tests for validateInputs() — specifically the notification-provider
5
5
  * switch. Regressions here break every `swenyai/triage` action run because
@@ -65,6 +65,9 @@ function baseConfig(overrides = {}) {
65
65
  workspaceTools: [],
66
66
  rules: [],
67
67
  context: [],
68
+ offline: false,
69
+ fetchAuth: {},
70
+ cloudToken: "",
68
71
  ...overrides,
69
72
  };
70
73
  }
@@ -109,3 +112,64 @@ describe("validateInputs — notification provider", () => {
109
112
  expect(err).toContain("console");
110
113
  });
111
114
  });
115
+ describe("fetch.auth + offline parsing", () => {
116
+ it("parses offline flag", () => {
117
+ const config = parseCliInputs({ offline: true }, {});
118
+ expect(config.offline).toBe(true);
119
+ });
120
+ it("defaults fetchAuth to {} and offline to false", () => {
121
+ const config = parseCliInputs({}, {});
122
+ expect(config.offline).toBe(false);
123
+ expect(config.fetchAuth).toEqual({});
124
+ });
125
+ it("parses fetch.auth from file config", () => {
126
+ const config = parseCliInputs({}, { "fetch.auth": { "api.example.com": "MY_TOKEN" } });
127
+ expect(config.fetchAuth).toEqual({ "api.example.com": "MY_TOKEN" });
128
+ });
129
+ });
130
+ describe("parseCliInputs — cloud token", () => {
131
+ it("reads SWENY_CLOUD_TOKEN from env", () => {
132
+ const original = process.env.SWENY_CLOUD_TOKEN;
133
+ process.env.SWENY_CLOUD_TOKEN = "sweny_pk_test123";
134
+ try {
135
+ const config = parseCliInputs({});
136
+ expect(config.cloudToken).toBe("sweny_pk_test123");
137
+ }
138
+ finally {
139
+ if (original === undefined)
140
+ delete process.env.SWENY_CLOUD_TOKEN;
141
+ else
142
+ process.env.SWENY_CLOUD_TOKEN = original;
143
+ }
144
+ });
145
+ it("reads cloud-token from config file", () => {
146
+ const config = parseCliInputs({}, { "cloud-token": "sweny_pk_fromfile" });
147
+ expect(config.cloudToken).toBe("sweny_pk_fromfile");
148
+ });
149
+ it("env var overrides config file", () => {
150
+ const original = process.env.SWENY_CLOUD_TOKEN;
151
+ process.env.SWENY_CLOUD_TOKEN = "sweny_pk_env";
152
+ try {
153
+ const config = parseCliInputs({}, { "cloud-token": "sweny_pk_file" });
154
+ expect(config.cloudToken).toBe("sweny_pk_env");
155
+ }
156
+ finally {
157
+ if (original === undefined)
158
+ delete process.env.SWENY_CLOUD_TOKEN;
159
+ else
160
+ process.env.SWENY_CLOUD_TOKEN = original;
161
+ }
162
+ });
163
+ it("defaults to empty string", () => {
164
+ const original = process.env.SWENY_CLOUD_TOKEN;
165
+ delete process.env.SWENY_CLOUD_TOKEN;
166
+ try {
167
+ const config = parseCliInputs({});
168
+ expect(config.cloudToken).toBe("");
169
+ }
170
+ finally {
171
+ if (original !== undefined)
172
+ process.env.SWENY_CLOUD_TOKEN = original;
173
+ }
174
+ });
175
+ });
package/dist/cli/e2e.js CHANGED
@@ -830,9 +830,11 @@ export async function runE2eRun(options) {
830
830
  runResults.push({ file: fileName, passed: false });
831
831
  continue;
832
832
  }
833
- // Replace template vars in node instructions
833
+ // Replace template vars in node instructions (e2e workflows always use string instructions)
834
834
  for (const node of Object.values(workflow.nodes)) {
835
- node.instruction = resolveTemplateVars(node.instruction, vars);
835
+ if (typeof node.instruction === "string") {
836
+ node.instruction = resolveTemplateVars(node.instruction, vars);
837
+ }
836
838
  }
837
839
  // Build skills + Claude client
838
840
  const skills = createSkillMap(configuredSkills(process.env, cwd));
@@ -247,7 +247,13 @@ describe("buildFlowNodes", () => {
247
247
  const { nodes } = buildFlowNodes(flow);
248
248
  for (const [id, node] of Object.entries(nodes)) {
249
249
  expect(node.name, `${id}.name`).toBeTruthy();
250
- expect(node.instruction.length, `${id}.instruction`).toBeGreaterThan(0);
250
+ const instr = node.instruction;
251
+ if (typeof instr === "string") {
252
+ expect(instr.length, `${id}.instruction`).toBeGreaterThan(0);
253
+ }
254
+ else {
255
+ expect(instr, `${id}.instruction`).toBeTruthy();
256
+ }
251
257
  expect(Array.isArray(node.skills), `${id}.skills`).toBe(true);
252
258
  }
253
259
  });
@@ -607,7 +613,8 @@ describe("template variable completeness — all {vars} in instructions are reso
607
613
  it(`${flow.type}: all template vars in instructions resolve to values`, () => {
608
614
  const wf = buildFlowWorkflow(flow, "http://localhost:3000");
609
615
  for (const [nodeId, node] of Object.entries(wf.nodes)) {
610
- const resolved = resolveTemplateVars(node.instruction, vars);
616
+ const instrText = typeof node.instruction === "string" ? node.instruction : "";
617
+ const resolved = resolveTemplateVars(instrText, vars);
611
618
  // After resolution, no {word} placeholders should remain
612
619
  // (except for agent-browser refs like @<ref> which are not {vars})
613
620
  const unresolvedVars = resolved.match(/\{(\w+)\}/g) || [];
package/dist/cli/main.js CHANGED
@@ -29,6 +29,7 @@ import { c, formatBanner, getStepDetails, formatStepLine, formatDagResultHuman,
29
29
  import { checkProviderConnectivity } from "./check.js";
30
30
  import { registerSetupCommand } from "./setup.js";
31
31
  import { registerPublishCommand } from "./publish.js";
32
+ import { reportToCloud } from "./cloud-report.js";
32
33
  // ── Stream observer (NDJSON) ────────────────────────────────────────
33
34
  /**
34
35
  * Create an observer that writes NDJSON ExecutionEvents to stdout.
@@ -324,10 +325,9 @@ triageCmd.action(async (options) => {
324
325
  ...(config.observabilityCredentials.tableName && {
325
326
  betterstackTableName: config.observabilityCredentials.tableName,
326
327
  }),
327
- // Structured rules/context for executor
328
+ // Structured rules/context for executor (URLs resolved eagerly by loadAdditionalContext)
328
329
  rules,
329
330
  context: fullContext,
330
- // URLs for the prepare node to fetch at runtime
331
331
  rulesUrls,
332
332
  contextUrls,
333
333
  };
@@ -337,6 +337,10 @@ triageCmd.action(async (options) => {
337
337
  claude,
338
338
  observer,
339
339
  logger: consoleLogger,
340
+ cwd: process.cwd(),
341
+ env: process.env,
342
+ fetchAuth: config.fetchAuth,
343
+ offline: config.offline,
340
344
  });
341
345
  const durationMs = Date.now() - runStart;
342
346
  // Output
@@ -360,6 +364,13 @@ triageCmd.action(async (options) => {
360
364
  console.error(c.subtle(` ⚠ could not write GITHUB_STEP_SUMMARY: ${err instanceof Error ? err.message : err}`));
361
365
  }
362
366
  }
367
+ // Report to SWEny Cloud (best-effort, never block the run)
368
+ try {
369
+ await reportToCloud(results, durationMs, config, "triage");
370
+ }
371
+ catch {
372
+ // silent — cloud reporting is optional
373
+ }
363
374
  // Terminal bell
364
375
  if (config.bell)
365
376
  process.stderr.write("\x07");
@@ -420,6 +431,7 @@ implementCmd.action(async (issueId, options) => {
420
431
  mcpServers,
421
432
  });
422
433
  console.log(chalk.cyan(`\n sweny implement ${issueId}\n`));
434
+ const implRunStart = Date.now();
423
435
  const isTTY = process.stderr.isTTY ?? false;
424
436
  const implProgressObserver = (event) => {
425
437
  switch (event.type) {
@@ -477,6 +489,10 @@ implementCmd.action(async (issueId, options) => {
477
489
  claude,
478
490
  observer,
479
491
  logger: consoleLogger,
492
+ cwd: process.cwd(),
493
+ env: process.env,
494
+ fetchAuth: config.fetchAuth,
495
+ offline: config.offline,
480
496
  });
481
497
  const hasFailed = [...results.values()].some((r) => r.status === "failed");
482
498
  if (hasFailed) {
@@ -491,6 +507,13 @@ implementCmd.action(async (issueId, options) => {
491
507
  else {
492
508
  console.log(chalk.green(`\n Implement workflow completed\n`));
493
509
  }
510
+ // Report to SWEny Cloud (best-effort)
511
+ try {
512
+ await reportToCloud(results, Date.now() - implRunStart, config, "implement");
513
+ }
514
+ catch {
515
+ // silent
516
+ }
494
517
  process.exit(0);
495
518
  }
496
519
  catch (err) {
@@ -540,6 +563,7 @@ export async function workflowRunAction(file, options) {
540
563
  }
541
564
  process.exit(0);
542
565
  }
566
+ const runStart = Date.now();
543
567
  const fileConfig = loadConfigFile();
544
568
  const config = parseCliInputs(options, fileConfig);
545
569
  const isJson = Boolean(options.json);
@@ -659,6 +683,10 @@ export async function workflowRunAction(file, options) {
659
683
  claude,
660
684
  observer,
661
685
  logger: consoleLogger,
686
+ cwd: process.cwd(),
687
+ env: process.env,
688
+ fetchAuth: config.fetchAuth,
689
+ offline: config.offline,
662
690
  });
663
691
  if (isJson) {
664
692
  process.stdout.write(JSON.stringify(Object.fromEntries(results), null, 2) + "\n");
@@ -674,7 +702,21 @@ export async function workflowRunAction(file, options) {
674
702
  }
675
703
  process.stdout.write(toMermaidBlock(workflow, { state, trace, title: workflow.name }) + "\n");
676
704
  }
705
+ // Report to SWEny Cloud (best-effort)
706
+ try {
707
+ await reportToCloud(results, Date.now() - runStart, config, workflow.id);
708
+ }
709
+ catch {
710
+ // silent
711
+ }
677
712
  const hasFailed = [...results.values()].some((r) => r.status === "failed");
713
+ // Report to SWEny Cloud (best-effort)
714
+ try {
715
+ await reportToCloud(results, 0, config, workflow.id);
716
+ }
717
+ catch {
718
+ // silent
719
+ }
678
720
  if (hasFailed) {
679
721
  console.error(chalk.red(` Workflow failed\n`));
680
722
  process.exit(1);
@@ -804,9 +846,12 @@ workflowCmd
804
846
  .action(workflowExportAction);
805
847
  workflowCmd
806
848
  .command("create <description>")
807
- .description("Generate a new workflow from a natural language description")
849
+ .description("[DEPRECATED] Use `sweny new` and pick 'Describe your own'")
808
850
  .option("--json", "Output workflow JSON to stdout (no interactive prompt)")
809
851
  .action(async (description, options) => {
852
+ if (!options.json) {
853
+ console.warn("\x1B[33m ⚠ `sweny workflow create` is deprecated. Use `sweny new` instead.\x1B[0m\n");
854
+ }
810
855
  const skills = configuredSkills();
811
856
  const claude = new ClaudeClient({
812
857
  maxTurns: 3,
@@ -44,6 +44,7 @@ function fakeTrace(steps) {
44
44
  iteration: s.iteration ?? 1,
45
45
  })),
46
46
  edges: [],
47
+ sources: {},
47
48
  };
48
49
  }
49
50
  describe("formatDagResultMarkdown", () => {
@@ -0,0 +1 @@
1
+ export {};