newo 3.6.2 → 3.7.1

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 (51) hide show
  1. package/CHANGELOG.md +44 -3
  2. package/README.md +61 -0
  3. package/dist/cli/commands/check.d.ts +3 -0
  4. package/dist/cli/commands/check.js +15 -0
  5. package/dist/cli/commands/format.d.ts +3 -0
  6. package/dist/cli/commands/format.js +105 -0
  7. package/dist/cli/commands/help.js +13 -0
  8. package/dist/cli/commands/lint.d.ts +3 -0
  9. package/dist/cli/commands/lint.js +195 -0
  10. package/dist/cli-new/di/tokens.d.ts +1 -1
  11. package/dist/cli.js +45 -9
  12. package/dist/domain/strategies/sync/AttributeSyncStrategy.js +38 -8
  13. package/dist/lint/config.d.ts +4 -0
  14. package/dist/lint/config.js +14 -0
  15. package/dist/lint/discovery.d.ts +34 -0
  16. package/dist/lint/discovery.js +112 -0
  17. package/dist/lint/live-schema.d.ts +20 -0
  18. package/dist/lint/live-schema.js +52 -0
  19. package/dist/lint/reporters/index.d.ts +4 -0
  20. package/dist/lint/reporters/index.js +19 -0
  21. package/dist/lint/reporters/json.d.ts +3 -0
  22. package/dist/lint/reporters/json.js +6 -0
  23. package/dist/lint/reporters/sarif.d.ts +3 -0
  24. package/dist/lint/reporters/sarif.js +47 -0
  25. package/dist/lint/reporters/text.d.ts +3 -0
  26. package/dist/lint/reporters/text.js +51 -0
  27. package/dist/lint/reporters/types.d.ts +6 -0
  28. package/dist/lint/reporters/types.js +2 -0
  29. package/dist/sync/attributes.js +38 -12
  30. package/dist/sync/conversations.d.ts +1 -1
  31. package/dist/sync/conversations.js +240 -193
  32. package/dist/sync/json-attr-utils.d.ts +67 -0
  33. package/dist/sync/json-attr-utils.js +98 -0
  34. package/package.json +3 -1
  35. package/src/cli/commands/check.ts +21 -0
  36. package/src/cli/commands/format.ts +131 -0
  37. package/src/cli/commands/help.ts +13 -0
  38. package/src/cli/commands/lint.ts +246 -0
  39. package/src/cli.ts +50 -9
  40. package/src/domain/strategies/sync/AttributeSyncStrategy.ts +45 -8
  41. package/src/lint/config.ts +17 -0
  42. package/src/lint/discovery.ts +148 -0
  43. package/src/lint/live-schema.ts +62 -0
  44. package/src/lint/reporters/index.ts +22 -0
  45. package/src/lint/reporters/json.ts +12 -0
  46. package/src/lint/reporters/sarif.ts +59 -0
  47. package/src/lint/reporters/text.ts +58 -0
  48. package/src/lint/reporters/types.ts +7 -0
  49. package/src/sync/attributes.ts +43 -14
  50. package/src/sync/conversations.ts +265 -212
  51. package/src/sync/json-attr-utils.ts +95 -0
@@ -0,0 +1,4 @@
1
+ import type { NewoLintConfig } from 'newo-dsl-analyzer';
2
+ export type { NewoLintConfig } from 'newo-dsl-analyzer';
3
+ export declare function loadNewoLintConfig(startDir?: string): NewoLintConfig;
4
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Lint config resolution for the newo CLI.
3
+ *
4
+ * Looks for `.neworc.yaml` / `.neworc.yml` / `.neworc.json` starting at
5
+ * the cwd and walking up to the filesystem root. Thin wrapper around
6
+ * newo-dsl-analyzer's `loadConfig` so consumers can override location
7
+ * per command if they need to.
8
+ */
9
+ import path from 'path';
10
+ import { loadConfig as analyzerLoadConfig } from 'newo-dsl-analyzer';
11
+ export function loadNewoLintConfig(startDir = process.cwd()) {
12
+ return analyzerLoadConfig(path.resolve(startDir)) ?? {};
13
+ }
14
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1,34 @@
1
+ import { type FormatVersion } from '../format/types.js';
2
+ import type { CustomerConfig } from '../types.js';
3
+ export interface DiscoveryOptions {
4
+ /** If set, restrict to one format's extensions only. */
5
+ format?: FormatVersion;
6
+ /** If true, include only files that hash-differ from `.newo/{customer}/hashes.json`. */
7
+ changedOnly?: boolean;
8
+ /** Additional absolute paths to skip. */
9
+ ignore?: string[];
10
+ }
11
+ export interface DiscoveredFile {
12
+ /** Absolute path on disk. */
13
+ absPath: string;
14
+ /** Path relative to the customer root (for display / reports). */
15
+ relPath: string;
16
+ /** Extension (including leading dot). */
17
+ ext: string;
18
+ }
19
+ /**
20
+ * Discover script files under a customer's tree.
21
+ * Respects format when given (else walks all recognized extensions).
22
+ */
23
+ export declare function discoverCustomerFiles(customer: CustomerConfig, opts?: DiscoveryOptions): Promise<DiscoveredFile[]>;
24
+ /**
25
+ * Discover files under an arbitrary directory.
26
+ * Used when the user passes explicit paths to `newo lint some/dir`.
27
+ */
28
+ export declare function discoverFromPath(inputPath: string, opts?: DiscoveryOptions): Promise<DiscoveredFile[]>;
29
+ /**
30
+ * Default root for lint invocations with no path arguments - the
31
+ * `newo_customers/` directory at the cwd.
32
+ */
33
+ export declare function defaultRoot(): string;
34
+ //# sourceMappingURL=discovery.d.ts.map
@@ -0,0 +1,112 @@
1
+ /**
2
+ * File discovery for `newo lint` / `newo format` / `newo check`.
3
+ *
4
+ * Walks a customer's tree (or any directory passed on the CLI), filters
5
+ * by format-aware extensions, and optionally narrows to files changed
6
+ * since the last push by consulting `.newo/{customer}/hashes.json`.
7
+ */
8
+ import fs from 'fs-extra';
9
+ import path from 'path';
10
+ import { NEWO_CUSTOMERS_DIR, customerDir } from '../fsutil.js';
11
+ import { loadHashes } from '../hash.js';
12
+ import { sha256 } from '../hash.js';
13
+ import { ALL_SCRIPT_EXTENSIONS, CLI_V1_EXTENSIONS, NEWO_V2_EXTENSIONS, } from '../format/types.js';
14
+ /**
15
+ * Discover script files under a customer's tree.
16
+ * Respects format when given (else walks all recognized extensions).
17
+ */
18
+ export async function discoverCustomerFiles(customer, opts = {}) {
19
+ const root = customerDir(customer.idn);
20
+ if (!(await fs.pathExists(root)))
21
+ return [];
22
+ const exts = pickExtensions(opts.format);
23
+ const ignoreSet = new Set(opts.ignore ?? []);
24
+ const hits = await walkForExtensions(root, exts, ignoreSet);
25
+ if (!opts.changedOnly) {
26
+ return hits.map(absPath => toDiscoveredFile(absPath, root));
27
+ }
28
+ const stored = await loadHashes(customer.idn);
29
+ const changed = [];
30
+ for (const absPath of hits) {
31
+ const current = sha256(await fs.readFile(absPath, 'utf8'));
32
+ if (stored[absPath] !== current) {
33
+ changed.push(toDiscoveredFile(absPath, root));
34
+ }
35
+ }
36
+ return changed;
37
+ }
38
+ /**
39
+ * Discover files under an arbitrary directory.
40
+ * Used when the user passes explicit paths to `newo lint some/dir`.
41
+ */
42
+ export async function discoverFromPath(inputPath, opts = {}) {
43
+ const abs = path.resolve(inputPath);
44
+ if (!(await fs.pathExists(abs)))
45
+ return [];
46
+ const exts = pickExtensions(opts.format);
47
+ const ignoreSet = new Set(opts.ignore ?? []);
48
+ const stat = await fs.stat(abs);
49
+ let hits;
50
+ if (stat.isFile()) {
51
+ hits = exts.includes(path.extname(abs)) ? [abs] : [];
52
+ }
53
+ else {
54
+ hits = await walkForExtensions(abs, exts, ignoreSet);
55
+ }
56
+ const root = stat.isDirectory() ? abs : path.dirname(abs);
57
+ return hits.map(p => toDiscoveredFile(p, root));
58
+ }
59
+ function pickExtensions(format) {
60
+ if (!format)
61
+ return [...ALL_SCRIPT_EXTENSIONS];
62
+ const map = format === 'newo_v2' ? NEWO_V2_EXTENSIONS : CLI_V1_EXTENSIONS;
63
+ return Object.values(map);
64
+ }
65
+ function toDiscoveredFile(absPath, root) {
66
+ return {
67
+ absPath,
68
+ relPath: path.relative(root, absPath),
69
+ ext: path.extname(absPath),
70
+ };
71
+ }
72
+ async function walkForExtensions(dir, exts, ignore) {
73
+ const out = [];
74
+ const stack = [dir];
75
+ while (stack.length > 0) {
76
+ const current = stack.pop();
77
+ if (ignore.has(current))
78
+ continue;
79
+ let entries;
80
+ try {
81
+ entries = await fs.readdir(current, { withFileTypes: true });
82
+ }
83
+ catch {
84
+ continue;
85
+ }
86
+ for (const entry of entries) {
87
+ // Skip hidden dirs, node_modules, and the .newo state directory.
88
+ if (entry.name.startsWith('.'))
89
+ continue;
90
+ if (entry.name === 'node_modules')
91
+ continue;
92
+ const full = path.join(current, entry.name);
93
+ if (ignore.has(full))
94
+ continue;
95
+ if (entry.isDirectory()) {
96
+ stack.push(full);
97
+ }
98
+ else if (exts.includes(path.extname(entry.name))) {
99
+ out.push(full);
100
+ }
101
+ }
102
+ }
103
+ return out.sort();
104
+ }
105
+ /**
106
+ * Default root for lint invocations with no path arguments - the
107
+ * `newo_customers/` directory at the cwd.
108
+ */
109
+ export function defaultRoot() {
110
+ return NEWO_CUSTOMERS_DIR;
111
+ }
112
+ //# sourceMappingURL=discovery.js.map
@@ -0,0 +1,20 @@
1
+ import type { CustomerConfig } from '../types.js';
2
+ export interface LiveSchemaSnapshot {
3
+ actions: Array<{
4
+ name: string;
5
+ [k: string]: unknown;
6
+ }>;
7
+ fetchedAt: string;
8
+ }
9
+ export declare function liveSchemaCachePath(customerIdn: string): Promise<string>;
10
+ /**
11
+ * Fetch the current action catalog from NEWO and cache it.
12
+ * Returns a snapshot ready to pass to `createLinter`.
13
+ */
14
+ export declare function refreshLiveSchema(customer: CustomerConfig): Promise<LiveSchemaSnapshot>;
15
+ /**
16
+ * Load the cached snapshot if present. Returns null when the cache is
17
+ * missing or corrupt (caller should fall back to bundled schemas).
18
+ */
19
+ export declare function loadCachedLiveSchema(customerIdn: string): Promise<LiveSchemaSnapshot | null>;
20
+ //# sourceMappingURL=live-schema.d.ts.map
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Live schema refresh: hits `/api/v1/script/actions` via the existing
3
+ * NEWO api client, caches the response to `.newo/{customer}/actions.json`,
4
+ * and returns an object shaped for `createLinter({ schemas: { kind: 'inline', ... }})`.
5
+ */
6
+ import fs from 'fs-extra';
7
+ import path from 'path';
8
+ import { customerStateDir } from '../fsutil.js';
9
+ import { getValidAccessToken } from '../auth.js';
10
+ import { makeClient, getScriptActions } from '../api.js';
11
+ export async function liveSchemaCachePath(customerIdn) {
12
+ const dir = customerStateDir(customerIdn);
13
+ await fs.ensureDir(dir);
14
+ return path.join(dir, 'actions.json');
15
+ }
16
+ /**
17
+ * Fetch the current action catalog from NEWO and cache it.
18
+ * Returns a snapshot ready to pass to `createLinter`.
19
+ */
20
+ export async function refreshLiveSchema(customer) {
21
+ const token = await getValidAccessToken(customer);
22
+ const client = await makeClient(false, token);
23
+ const actions = await getScriptActions(client);
24
+ const snapshot = {
25
+ actions: actions.map((a) => ({
26
+ name: a.idn ?? a.title,
27
+ title: a.title,
28
+ ...(a.idn !== undefined ? { idn: a.idn } : {}),
29
+ arguments: a.arguments,
30
+ })),
31
+ fetchedAt: new Date().toISOString(),
32
+ };
33
+ const cachePath = await liveSchemaCachePath(customer.idn);
34
+ await fs.writeJson(cachePath, snapshot, { spaces: 2 });
35
+ return snapshot;
36
+ }
37
+ /**
38
+ * Load the cached snapshot if present. Returns null when the cache is
39
+ * missing or corrupt (caller should fall back to bundled schemas).
40
+ */
41
+ export async function loadCachedLiveSchema(customerIdn) {
42
+ const cachePath = await liveSchemaCachePath(customerIdn);
43
+ if (!(await fs.pathExists(cachePath)))
44
+ return null;
45
+ try {
46
+ return (await fs.readJson(cachePath));
47
+ }
48
+ catch {
49
+ return null;
50
+ }
51
+ }
52
+ //# sourceMappingURL=live-schema.js.map
@@ -0,0 +1,4 @@
1
+ import type { Reporter, ReporterName } from './types.js';
2
+ export type { Reporter, ReporterName } from './types.js';
3
+ export declare function pickReporter(name: ReporterName | string | undefined): Reporter;
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,19 @@
1
+ import { textReporter } from './text.js';
2
+ import { jsonReporter } from './json.js';
3
+ import { sarifReporter } from './sarif.js';
4
+ export function pickReporter(name) {
5
+ switch (name) {
6
+ case 'json':
7
+ return jsonReporter;
8
+ case 'sarif':
9
+ return sarifReporter;
10
+ case 'text':
11
+ case undefined:
12
+ case '':
13
+ return textReporter;
14
+ default:
15
+ console.warn(`Unknown --format value '${name}', defaulting to text.`);
16
+ return textReporter;
17
+ }
18
+ }
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,3 @@
1
+ import type { Reporter } from './types.js';
2
+ export declare const jsonReporter: Reporter;
3
+ //# sourceMappingURL=json.d.ts.map
@@ -0,0 +1,6 @@
1
+ export const jsonReporter = {
2
+ write(report) {
3
+ return JSON.stringify(report, null, 2);
4
+ },
5
+ };
6
+ //# sourceMappingURL=json.js.map
@@ -0,0 +1,3 @@
1
+ import type { Reporter } from './types.js';
2
+ export declare const sarifReporter: Reporter;
3
+ //# sourceMappingURL=sarif.d.ts.map
@@ -0,0 +1,47 @@
1
+ export const sarifReporter = {
2
+ write(report) {
3
+ const sarif = {
4
+ $schema: 'https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json',
5
+ version: '2.1.0',
6
+ runs: [
7
+ {
8
+ tool: {
9
+ driver: {
10
+ name: 'newo-lint',
11
+ informationUri: 'https://github.com/sabbah13/newo-cli',
12
+ rules: [],
13
+ },
14
+ },
15
+ results: report.results.flatMap(r => r.diagnostics.map(d => buildResult(r.filePath, d))),
16
+ },
17
+ ],
18
+ };
19
+ return JSON.stringify(sarif, null, 2);
20
+ },
21
+ };
22
+ function buildResult(filePath, d) {
23
+ return {
24
+ ruleId: d.code,
25
+ level: d.severity === 'error' ? 'error' : d.severity === 'warning' ? 'warning' : 'note',
26
+ message: { text: d.message },
27
+ locations: [
28
+ {
29
+ physicalLocation: {
30
+ artifactLocation: { uri: toUri(filePath) },
31
+ region: {
32
+ startLine: d.range.start.line,
33
+ startColumn: d.range.start.column,
34
+ endLine: d.range.end.line,
35
+ endColumn: d.range.end.column,
36
+ },
37
+ },
38
+ },
39
+ ],
40
+ };
41
+ }
42
+ function toUri(absPath) {
43
+ // SARIF artifact URIs should be workspace-relative when possible.
44
+ const rel = absPath.replace(process.cwd() + '/', '');
45
+ return rel.replace(/\\/g, '/');
46
+ }
47
+ //# sourceMappingURL=sarif.js.map
@@ -0,0 +1,3 @@
1
+ import type { Reporter } from './types.js';
2
+ export declare const textReporter: Reporter;
3
+ //# sourceMappingURL=text.d.ts.map
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Human-readable terminal reporter. Mirrors the ESLint 'stylish' layout:
3
+ *
4
+ * path/to/file.jinja
5
+ * 12:5 error Unknown skill: foo. Did you mean: bar? E100
6
+ * ...
7
+ *
8
+ * 2 problems (1 error, 1 warning)
9
+ */
10
+ import path from 'path';
11
+ const RED = '\x1b[31m';
12
+ const YELLOW = '\x1b[33m';
13
+ const CYAN = '\x1b[36m';
14
+ const GREY = '\x1b[90m';
15
+ const RESET = '\x1b[0m';
16
+ const BOLD = '\x1b[1m';
17
+ export const textReporter = {
18
+ write(report) {
19
+ const lines = [];
20
+ const filesWithIssues = report.results.filter(r => r.diagnostics.length > 0);
21
+ for (const result of filesWithIssues) {
22
+ lines.push(renderFile(result));
23
+ lines.push('');
24
+ }
25
+ lines.push(renderSummary(report));
26
+ return lines.join('\n');
27
+ },
28
+ };
29
+ function renderFile(result) {
30
+ const rel = path.relative(process.cwd(), result.filePath);
31
+ const header = `${BOLD}${CYAN}${rel}${RESET}`;
32
+ const rows = result.diagnostics.map(d => {
33
+ const loc = `${d.range.start.line}:${d.range.start.column}`;
34
+ const sev = d.severity === 'error'
35
+ ? `${RED}error${RESET}`
36
+ : d.severity === 'warning'
37
+ ? `${YELLOW}warning${RESET}`
38
+ : `${GREY}${d.severity}${RESET}`;
39
+ return ` ${loc.padEnd(7)} ${sev.padEnd(16)} ${d.message} ${GREY}${d.code}${RESET}`;
40
+ });
41
+ return [header, ...rows].join('\n');
42
+ }
43
+ function renderSummary(report) {
44
+ const total = report.errorCount + report.warningCount;
45
+ if (total === 0) {
46
+ return `${GREY}No issues found.${RESET}`;
47
+ }
48
+ const color = report.errorCount > 0 ? RED : YELLOW;
49
+ return `${color}${BOLD}${total} problems${RESET} (${report.errorCount} error${report.errorCount === 1 ? '' : 's'}, ${report.warningCount} warning${report.warningCount === 1 ? '' : 's'})`;
50
+ }
51
+ //# sourceMappingURL=text.js.map
@@ -0,0 +1,6 @@
1
+ import type { ProjectLintReport } from 'newo-dsl-analyzer';
2
+ export type ReporterName = 'text' | 'json' | 'sarif';
3
+ export interface Reporter {
4
+ write(report: ProjectLintReport): string;
5
+ }
6
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -7,6 +7,7 @@ import path from 'path';
7
7
  import fs from 'fs-extra';
8
8
  import yaml from 'js-yaml';
9
9
  import { patchYamlToPyyaml } from '../format/yaml-patch.js';
10
+ import { isJsonValueType, normalizeJsonValueForStorage, jsonValuesEqual } from './json-attr-utils.js';
10
11
  /**
11
12
  * Save customer attributes to YAML format and return content for hashing
12
13
  */
@@ -28,16 +29,23 @@ export async function saveCustomerAttributes(client, customer, verbose = false)
28
29
  if (attr.id) {
29
30
  idMapping[attr.idn] = attr.id;
30
31
  }
31
- // Special handling for complex JSON string values
32
+ // Coerce JSON-typed values to a STRING. The API can return the value
33
+ // as a parsed object for `value_type: json` attributes; if we let
34
+ // yaml.dump serialize that as a YAML structure the next push sends
35
+ // `{"value": {...}}` instead of `{"value": "..."}` and the Workflow
36
+ // Builder canvas breaks. See src/sync/json-attr-utils.ts for the
37
+ // full rationale.
32
38
  let processedValue = attr.value;
33
- if (typeof attr.value === 'string' && attr.value.startsWith('[{') && attr.value.endsWith('}]')) {
39
+ if (isJsonValueType(attr.value_type)) {
40
+ processedValue = normalizeJsonValueForStorage(attr.value);
41
+ }
42
+ else if (typeof attr.value === 'string' && attr.value.startsWith('[{') && attr.value.endsWith('}]')) {
43
+ // Legacy: reformat array-of-objects JSON strings for readability
34
44
  try {
35
- // Parse and reformat JSON for better readability
36
45
  const parsed = JSON.parse(attr.value);
37
- processedValue = JSON.stringify(parsed, null, 0); // No extra spacing, but valid JSON
46
+ processedValue = JSON.stringify(parsed, null, 0); // compact, valid JSON
38
47
  }
39
48
  catch (e) {
40
- // Keep original if parsing fails
41
49
  processedValue = attr.value;
42
50
  }
43
51
  }
@@ -114,9 +122,13 @@ export async function saveProjectAttributes(client, customer, projectId, project
114
122
  if (attr.id) {
115
123
  idMapping[attr.idn] = attr.id;
116
124
  }
117
- // Special handling for complex JSON string values
125
+ // Coerce JSON-typed values to a STRING. See json-attr-utils.ts for
126
+ // why this matters (Workflow Builder canvas blank-screen bug).
118
127
  let processedValue = attr.value;
119
- if (typeof attr.value === 'string' && attr.value.startsWith('[{') && attr.value.endsWith('}]')) {
128
+ if (isJsonValueType(attr.value_type)) {
129
+ processedValue = normalizeJsonValueForStorage(attr.value);
130
+ }
131
+ else if (typeof attr.value === 'string' && attr.value.startsWith('[{') && attr.value.endsWith('}]')) {
120
132
  try {
121
133
  const parsed = JSON.parse(attr.value);
122
134
  processedValue = JSON.stringify(parsed, null, 0);
@@ -243,17 +255,31 @@ export async function pushProjectAttributes(client, customer, projectId, project
243
255
  }
244
256
  // Value type is already parsed (we removed !enum tags above)
245
257
  const valueType = localAttr.value_type;
246
- // Check if value changed (use ?? to preserve 0, false, empty string)
247
- const localValue = String(localAttr.value ?? '');
248
- const remoteValue = String(remoteAttr.value ?? '');
249
- if (localValue !== remoteValue) {
258
+ const isJson = isJsonValueType(valueType);
259
+ // Check if value changed.
260
+ // For JSON-typed values, compare canonical (compact) JSON so that
261
+ // pretty- vs compact-printed forms don't register as changes and
262
+ // string vs object representations compare equal. For everything
263
+ // else, fall back to the existing String() comparison (which still
264
+ // preserves 0, false, "" via ??).
265
+ const valuesAreEqual = isJson
266
+ ? jsonValuesEqual(localAttr.value, remoteAttr.value)
267
+ : String(localAttr.value ?? '') === String(remoteAttr.value ?? '');
268
+ if (!valuesAreEqual) {
250
269
  if (verbose)
251
270
  console.log(` 🔄 Updating project attribute: ${localAttr.idn}`);
252
271
  try {
272
+ // Always send JSON-typed values as a STRING. If the API or our
273
+ // YAML loader handed us an object, the platform stores it
274
+ // differently from the original string and the Workflow Builder
275
+ // canvas blanks out.
276
+ const valueToSend = isJson
277
+ ? normalizeJsonValueForStorage(localAttr.value)
278
+ : localAttr.value;
253
279
  const attributeToUpdate = {
254
280
  id: attributeId,
255
281
  idn: localAttr.idn,
256
- value: localAttr.value,
282
+ value: valueToSend,
257
283
  title: localAttr.title,
258
284
  description: localAttr.description,
259
285
  group: localAttr.group,
@@ -1,7 +1,7 @@
1
1
  import type { AxiosInstance } from 'axios';
2
2
  import type { CustomerConfig, ConversationOptions } from '../types.js';
3
3
  /**
4
- * Pull conversations for a customer and save to YAML
4
+ * Pull conversations for a customer and save incrementally.
5
5
  */
6
6
  export declare function pullConversations(client: AxiosInstance, customer: CustomerConfig, options?: ConversationOptions, verbose?: boolean): Promise<void>;
7
7
  //# sourceMappingURL=conversations.d.ts.map