@sweny-ai/core 0.1.107 → 0.1.108

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.
@@ -47,7 +47,10 @@ const gitlab = {
47
47
  if (!creds.GITLAB_TOKEN)
48
48
  return undefined;
49
49
  const env = { GITLAB_PERSONAL_ACCESS_TOKEN: creds.GITLAB_TOKEN };
50
- const baseUrl = creds.GITLAB_URL || "https://gitlab.com";
50
+ // Normalize trailing slash(es) so a pasted "https://gl.corp.com/" (or even
51
+ // the canonical "https://gitlab.com/") does not produce a double-slash
52
+ // "//api/v4". The /+$ also collapses accidental multi-trailing-slash input.
53
+ const baseUrl = (creds.GITLAB_URL || "https://gitlab.com").replace(/\/+$/, "");
51
54
  if (baseUrl !== "https://gitlab.com")
52
55
  env.GITLAB_API_URL = `${baseUrl}/api/v4`;
53
56
  return {
@@ -7,6 +7,13 @@
7
7
  * or `node:crypto` into bundlers that target the browser.
8
8
  */
9
9
  import type { ResolvedSource, Source, SourceResolutionContext, SourceResolutionMap } from "./sources.js";
10
+ /**
11
+ * Error-message prefix used when a `url:` source cannot be fetched in
12
+ * `--offline` mode. Exported so callers that intentionally degrade to a default
13
+ * on this one failure (e.g. `templates.ts`) can detect it without coupling to
14
+ * the full message text.
15
+ */
16
+ export declare const SOURCE_OFFLINE_REQUIRES_FETCH = "SOURCE_OFFLINE_REQUIRES_FETCH";
10
17
  /**
11
18
  * Produce a stable 16-hex-char hash of `content` for use as a cache key /
12
19
  * change-detection ID.
@@ -12,6 +12,13 @@ import * as path from "node:path";
12
12
  import { normalizeSource } from "./sources.js";
13
13
  /** Schemes a `url:` source is allowed to use. Everything else is rejected. */
14
14
  const ALLOWED_URL_SCHEMES = new Set(["http:", "https:"]);
15
+ /**
16
+ * Error-message prefix used when a `url:` source cannot be fetched in
17
+ * `--offline` mode. Exported so callers that intentionally degrade to a default
18
+ * on this one failure (e.g. `templates.ts`) can detect it without coupling to
19
+ * the full message text.
20
+ */
21
+ export const SOURCE_OFFLINE_REQUIRES_FETCH = "SOURCE_OFFLINE_REQUIRES_FETCH";
15
22
  /** Default DNS resolver used when the context does not inject one. */
16
23
  const defaultDnsLookup = async (hostname) => {
17
24
  const records = await dns.lookup(hostname, { all: true });
@@ -80,7 +87,7 @@ export async function resolveSource(source, fieldPath, ctx) {
80
87
  }
81
88
  if (kind === "url") {
82
89
  if (ctx.offline) {
83
- throw new Error(`SOURCE_OFFLINE_REQUIRES_FETCH: cannot fetch ${value} in --offline mode (referenced by ${fieldPath}).`);
90
+ throw new Error(`${SOURCE_OFFLINE_REQUIRES_FETCH}: cannot fetch ${value} in --offline mode (referenced by ${fieldPath}).`);
84
91
  }
85
92
  // Validate type field on tagged URL forms — v1 only accepts "fetch" (the default).
86
93
  if (typeof source === "object" && "url" in source && source.type && source.type !== "fetch") {
@@ -34,7 +34,12 @@ export interface SourceLoadOptions {
34
34
  }
35
35
  /**
36
36
  * Load a template from a file path or URL.
37
- * Returns the default if source is empty or loading fails.
37
+ *
38
+ * Returns the default only when the source is empty/unset, or when a URL source
39
+ * is intentionally skipped under `--offline`. A CONFIGURED source that fails to
40
+ * resolve (404, 403, SSRF block, read error) now THROWS instead of silently
41
+ * degrading to the built-in default — a typo'd or unauthorized template URL is
42
+ * a misconfiguration, not a no-op. This matches the executor's Source handling.
38
43
  *
39
44
  * Accepts the legacy `cwd?: string` signature for backward compat.
40
45
  */
@@ -52,6 +57,9 @@ export declare function resolveTemplates(config: {
52
57
  * Returns { resolved, urls } — resolved text for all sources; urls is kept
53
58
  * for API compat but will be empty since URLs now resolve eagerly.
54
59
  *
60
+ * A configured source that fails to resolve THROWS (matching the executor and
61
+ * `loadTemplate`); only the intentional `--offline` URL skip is swallowed.
62
+ *
55
63
  * Accepts the legacy `cwd?: string` signature for backward compat.
56
64
  */
57
65
  export declare function loadAdditionalContext(sources: string[], options?: SourceLoadOptions | string): Promise<{
package/dist/templates.js CHANGED
@@ -13,7 +13,7 @@
13
13
  */
14
14
  import * as path from "node:path";
15
15
  import { classifySource } from "./sources.js";
16
- import { resolveSource } from "./source-resolver.js";
16
+ import { resolveSource, SOURCE_OFFLINE_REQUIRES_FETCH } from "./source-resolver.js";
17
17
  import { consoleLogger } from "./types.js";
18
18
  export const DEFAULT_ISSUE_TEMPLATE = `## Summary
19
19
  <!-- One-line description of the issue -->
@@ -61,9 +61,26 @@ function buildCtx(options) {
61
61
  logger: consoleLogger,
62
62
  };
63
63
  }
64
+ /**
65
+ * True when a resolution error is the intentional `--offline` skip of a URL
66
+ * source. Offline mode is the one failure we deliberately swallow into the
67
+ * fallback: the operator explicitly asked to skip URL Sources. Every other
68
+ * failure (404/403/SSRF block/read error/unreachable) is a real
69
+ * misconfiguration and must surface, matching the executor's per-node Source
70
+ * resolution which hard-throws on all of these.
71
+ */
72
+ function isOfflineSkip(err) {
73
+ const msg = err instanceof Error ? err.message : String(err);
74
+ return msg.startsWith(SOURCE_OFFLINE_REQUIRES_FETCH);
75
+ }
64
76
  /**
65
77
  * Load a template from a file path or URL.
66
- * Returns the default if source is empty or loading fails.
78
+ *
79
+ * Returns the default only when the source is empty/unset, or when a URL source
80
+ * is intentionally skipped under `--offline`. A CONFIGURED source that fails to
81
+ * resolve (404, 403, SSRF block, read error) now THROWS instead of silently
82
+ * degrading to the built-in default — a typo'd or unauthorized template URL is
83
+ * a misconfiguration, not a no-op. This matches the executor's Source handling.
67
84
  *
68
85
  * Accepts the legacy `cwd?: string` signature for backward compat.
69
86
  */
@@ -76,9 +93,12 @@ export async function loadTemplate(source, fallback, options = {}) {
76
93
  return resolved.content;
77
94
  }
78
95
  catch (err) {
96
+ if (isOfflineSkip(err)) {
97
+ console.warn(`[templates] Skipping URL template in --offline mode, using default.`);
98
+ return fallback;
99
+ }
79
100
  const msg = err instanceof Error ? err.message : String(err);
80
- console.warn(`[templates] Failed to load template: ${msg}, using default`);
81
- return fallback;
101
+ throw new Error(`Failed to load configured template "${source.trim()}": ${msg}`);
82
102
  }
83
103
  }
84
104
  /**
@@ -98,6 +118,9 @@ export async function resolveTemplates(config, options = {}) {
98
118
  * Returns { resolved, urls } — resolved text for all sources; urls is kept
99
119
  * for API compat but will be empty since URLs now resolve eagerly.
100
120
  *
121
+ * A configured source that fails to resolve THROWS (matching the executor and
122
+ * `loadTemplate`); only the intentional `--offline` URL skip is swallowed.
123
+ *
101
124
  * Accepts the legacy `cwd?: string` signature for backward compat.
102
125
  */
103
126
  export async function loadAdditionalContext(sources, options = {}) {
@@ -123,8 +146,15 @@ export async function loadAdditionalContext(sources, options = {}) {
123
146
  }
124
147
  }
125
148
  catch (err) {
149
+ // Offline skip of a URL source is intentional; everything else (404,
150
+ // 403, SSRF block, read error) is a misconfiguration and must surface
151
+ // rather than silently dropping the configured context document.
152
+ if (isOfflineSkip(err)) {
153
+ console.warn(`[templates] Skipping URL context source "${trimmed}" in --offline mode.`);
154
+ continue;
155
+ }
126
156
  const msg = err instanceof Error ? err.message : String(err);
127
- console.warn(`[templates] Failed to load context source: ${msg}`);
157
+ throw new Error(`Failed to load configured context source "${trimmed}": ${msg}`);
128
158
  }
129
159
  }
130
160
  }
package/package.json CHANGED
@@ -1,12 +1,15 @@
1
1
  {
2
2
  "name": "@sweny-ai/core",
3
- "version": "0.1.107",
3
+ "version": "0.1.108",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "sweny": "./dist/cli/main.js"
7
7
  },
8
8
  "description": "Skill library, DAG workflow orchestration, and E2E browser testing powered by Claude",
9
9
  "license": "MIT",
10
+ "engines": {
11
+ "node": ">=20"
12
+ },
10
13
  "exports": {
11
14
  ".": "./dist/index.js",
12
15
  "./browser": "./dist/browser.js",
@@ -15,7 +18,8 @@
15
18
  "./workflows": "./dist/workflows/index.js",
16
19
  "./testing": "./dist/testing.js",
17
20
  "./schema": "./dist/schema.js",
18
- "./new": "./dist/cli/new.js"
21
+ "./new": "./dist/cli/new.js",
22
+ "./package.json": "./package.json"
19
23
  },
20
24
  "typesVersions": {
21
25
  "*": {