@dsh-workbench/shared 0.2.3 → 0.2.4

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.
@@ -16,7 +16,7 @@ export interface OpencliResult {
16
16
  readonly value: unknown;
17
17
  readonly at: number;
18
18
  }
19
- export type OpencliSession = 'persistent' | 'ephemeral';
19
+ export type OpencliSession = 'persistent' | 'ephemeral' | 'none';
20
20
  export declare function opencliCommandLine(command: string, argv: readonly string[], session?: OpencliSession): string;
21
21
  export interface Opencli {
22
22
  json(args: readonly string[], options?: {
package/dist/lib/text.js CHANGED
@@ -7,6 +7,23 @@ export function tailLines(text, lines = 6) {
7
7
  .split('\n');
8
8
  return all.slice(-lines).join('\n');
9
9
  }
10
+ function candidateStarts(raw) {
11
+ const starts = [];
12
+ for (let index = 0; index < raw.length; index += 1) {
13
+ const char = raw[index];
14
+ if (char !== '[' && char !== '{')
15
+ continue;
16
+ if (index === 0 || raw[index - 1] === '\n')
17
+ starts.push(index);
18
+ }
19
+ const earliest = [raw.indexOf('['), raw.indexOf('{')].filter((index) => index >= 0);
20
+ if (earliest.length > 0) {
21
+ const head = Math.min(...earliest);
22
+ if (!starts.includes(head))
23
+ starts.push(head);
24
+ }
25
+ return starts;
26
+ }
10
27
  export function parseJsonLoose(text) {
11
28
  const raw = String(text ?? '').trim();
12
29
  if (!raw)
@@ -15,21 +32,19 @@ export function parseJsonLoose(text) {
15
32
  return JSON.parse(raw);
16
33
  }
17
34
  catch {
18
- const starts = [raw.indexOf('['), raw.indexOf('{')].filter((index) => index >= 0);
19
- if (starts.length === 0)
20
- return undefined;
21
- const from = Math.min(...starts);
22
- const open = raw[from];
23
- const close = open === '[' ? ']' : '}';
24
- const to = raw.lastIndexOf(close);
25
- if (to <= from)
26
- return undefined;
27
- try {
28
- return JSON.parse(raw.slice(from, to + 1));
29
- }
30
- catch {
31
- return undefined;
35
+ for (const from of candidateStarts(raw)) {
36
+ const close = raw[from] === '[' ? ']' : '}';
37
+ const to = raw.lastIndexOf(close);
38
+ if (to <= from)
39
+ continue;
40
+ try {
41
+ return JSON.parse(raw.slice(from, to + 1));
42
+ }
43
+ catch {
44
+ continue;
45
+ }
32
46
  }
47
+ return undefined;
33
48
  }
34
49
  }
35
50
  const MARKDOWN_IMAGE = /!\[[^\]]*\]\([^)]*\)/g;
@@ -25,6 +25,7 @@ export interface OpencliCall {
25
25
  args: readonly string[];
26
26
  key?: string;
27
27
  workdir?: string;
28
+ session?: string;
28
29
  refresh?: boolean;
29
30
  }
30
31
  export declare function createFakeOpencli(replies?: Array<unknown | Error> | ((call: OpencliCall, index: number) => unknown | Error)): {
@@ -47,6 +47,7 @@ export function createFakeOpencli(replies = []) {
47
47
  args,
48
48
  ...(options.key === undefined ? {} : { key: options.key }),
49
49
  ...(options.workdir === undefined ? {} : { workdir: options.workdir }),
50
+ ...(options.session === undefined ? {} : { session: options.session }),
50
51
  };
51
52
  calls.push(call);
52
53
  const index = calls.length - 1;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dsh-workbench/shared",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
4
4
  "description": "工作台与模块共享的纯代码与契约类型:类型、纯逻辑、哑组件、平台解析。宿主侧的东西从 /host 进(不影响浏览器产物)。",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -36,7 +36,7 @@ export interface OpencliResult {
36
36
  readonly at: number;
37
37
  }
38
38
 
39
- export type OpencliSession = 'persistent' | 'ephemeral';
39
+ export type OpencliSession = 'persistent' | 'ephemeral' | 'none';
40
40
 
41
41
  export function opencliCommandLine(
42
42
  command: string,
@@ -58,6 +58,28 @@ describe('parseJsonLoose', () => {
58
58
  expect(parseJsonLoose('[1,2]\n完成')).toEqual([1, 2]);
59
59
  });
60
60
 
61
+ it('★ 噪音行自己带方括号时也不认错起点(真机:pagoda 的调试命令先打两行带 [] 的话)', () => {
62
+ const stdout = [
63
+ '数据源 [dify_dataset] 调试成功',
64
+ '结构类型: 3, 字段: code, name',
65
+ '[',
66
+ ' {',
67
+ ' "code": "dify_dataset",',
68
+ ' "success": "成功",',
69
+ ' "detail": "structure=3, keys=[code, name], fields=[{code=知识库ID}]"',
70
+ ' }',
71
+ ']',
72
+ ].join('\n');
73
+
74
+ expect(parseJsonLoose(stdout)).toEqual([
75
+ {
76
+ code: 'dify_dataset',
77
+ success: '成功',
78
+ detail: 'structure=3, keys=[code, name], fields=[{code=知识库ID}]',
79
+ },
80
+ ]);
81
+ });
82
+
61
83
  it('解析不出来给 undefined,让调用方报 coding-bad-output', () => {
62
84
  expect(parseJsonLoose('')).toBeUndefined();
63
85
  expect(parseJsonLoose('not json at all')).toBeUndefined();
package/src/lib/text.ts CHANGED
@@ -9,24 +9,38 @@ export function tailLines(text: string | null | undefined, lines = 6): string {
9
9
  return all.slice(-lines).join('\n');
10
10
  }
11
11
 
12
+ function candidateStarts(raw: string): number[] {
13
+ const starts: number[] = [];
14
+ for (let index = 0; index < raw.length; index += 1) {
15
+ const char = raw[index];
16
+ if (char !== '[' && char !== '{') continue;
17
+ if (index === 0 || raw[index - 1] === '\n') starts.push(index);
18
+ }
19
+ const earliest = [raw.indexOf('['), raw.indexOf('{')].filter((index) => index >= 0);
20
+ if (earliest.length > 0) {
21
+ const head = Math.min(...earliest);
22
+ if (!starts.includes(head)) starts.push(head);
23
+ }
24
+ return starts;
25
+ }
26
+
12
27
  export function parseJsonLoose(text: string | null | undefined): unknown {
13
28
  const raw = String(text ?? '').trim();
14
29
  if (!raw) return undefined;
15
30
  try {
16
31
  return JSON.parse(raw) as unknown;
17
32
  } catch {
18
- const starts = [raw.indexOf('['), raw.indexOf('{')].filter((index) => index >= 0);
19
- if (starts.length === 0) return undefined;
20
- const from = Math.min(...starts);
21
- const open = raw[from];
22
- const close = open === '[' ? ']' : '}';
23
- const to = raw.lastIndexOf(close);
24
- if (to <= from) return undefined;
25
- try {
26
- return JSON.parse(raw.slice(from, to + 1)) as unknown;
27
- } catch {
28
- return undefined;
33
+ for (const from of candidateStarts(raw)) {
34
+ const close = raw[from] === '[' ? ']' : '}';
35
+ const to = raw.lastIndexOf(close);
36
+ if (to <= from) continue;
37
+ try {
38
+ return JSON.parse(raw.slice(from, to + 1)) as unknown;
39
+ } catch {
40
+ continue;
41
+ }
29
42
  }
43
+ return undefined;
30
44
  }
31
45
  }
32
46
 
@@ -70,6 +70,7 @@ export interface OpencliCall {
70
70
  args: readonly string[];
71
71
  key?: string;
72
72
  workdir?: string;
73
+ session?: string;
73
74
  refresh?: boolean;
74
75
  }
75
76
 
@@ -84,6 +85,7 @@ export function createFakeOpencli(
84
85
  args,
85
86
  ...(options.key === undefined ? {} : { key: options.key }),
86
87
  ...(options.workdir === undefined ? {} : { workdir: options.workdir }),
88
+ ...(options.session === undefined ? {} : { session: options.session }),
87
89
  };
88
90
  calls.push(call);
89
91
  const index = calls.length - 1;