@dsh-workbench/adapter-supply 1.1.4 → 1.1.5

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.
@@ -25,6 +25,7 @@ export interface ProfileModule {
25
25
  readonly version: string;
26
26
  readonly registry?: string;
27
27
  readonly local?: boolean;
28
+ readonly fromRegistry?: boolean;
28
29
  }
29
30
  export declare function profileManifestOf(profileDir: string | null): Readonly<Record<string, unknown>> | undefined;
30
31
  export declare function profileModules(profileDir: string | null): readonly ProfileModule[];
@@ -39,6 +40,7 @@ export declare function declaredPluginCommands(profileDir: string | null): Reado
39
40
  export declare function readInstalledModule(profileDir: string | null, pkg: string): InstalledModule;
40
41
  export declare function isPackedArtifactSpec(spec: string): boolean;
41
42
  export declare function isLocalDependencySpec(spec: string): boolean;
43
+ export declare function isRegistryDependencySpec(spec: string): boolean;
42
44
  export interface ProfilePackage {
43
45
  readonly pkg: string;
44
46
  readonly version: string;
@@ -1,6 +1,6 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
- import { declarationProblemsOf, readDeclaration } from '@dsh-workbench/shared/host';
3
+ import { declarationProblemsOf, packageSourceOf, readDeclaration, scopeOf } from '@dsh-workbench/shared/host';
4
4
  const PACKAGE_NAME = /^(?:@[a-z0-9][a-z0-9._~-]*\/)?[a-z0-9][a-z0-9._~-]*$/;
5
5
  function asRecord(value) {
6
6
  return typeof value === 'object' && value !== null ? value : undefined;
@@ -39,14 +39,17 @@ export function profileModules(profileDir) {
39
39
  const found = [];
40
40
  for (const pkg of names) {
41
41
  const read = readInstalledModule(profileDir, pkg);
42
- if (read.kind === 'module')
42
+ if (read.kind === 'module') {
43
+ const spec = asText(dependencies[read.pkg]);
43
44
  found.push({
44
45
  pkg: read.pkg,
45
46
  unit: read.unit,
46
47
  version: read.version,
47
48
  ...(read.registry === undefined ? {} : { registry: read.registry }),
48
- local: isLocalDependencySpec(asText(dependencies[read.pkg])),
49
+ local: isLocalDependencySpec(spec),
50
+ fromRegistry: isRegistryDependencySpec(spec),
49
51
  });
52
+ }
50
53
  }
51
54
  return found;
52
55
  }
@@ -87,6 +90,51 @@ function registryFromLockfile(profileDir, pkg) {
87
90
  return undefined;
88
91
  return tarball.slice(0, cut);
89
92
  }
93
+ function unquoted(value) {
94
+ const quote = value.charAt(0);
95
+ if (value.length >= 2 && (quote === '"' || quote === "'") && value.endsWith(quote)) {
96
+ return value.slice(1, -1).trim();
97
+ }
98
+ return value;
99
+ }
100
+ function registryFromNpmrc(profileDir, pkg) {
101
+ let text;
102
+ try {
103
+ text = fs.readFileSync(path.join(profileDir, '.npmrc'), 'utf8');
104
+ }
105
+ catch {
106
+ return undefined;
107
+ }
108
+ const scope = scopeOf(pkg);
109
+ let fallback;
110
+ for (const line of text.split('\n')) {
111
+ const trimmed = line.trim();
112
+ if (trimmed === '' || trimmed.startsWith('#') || trimmed.startsWith(';'))
113
+ continue;
114
+ const separator = trimmed.indexOf('=');
115
+ if (separator <= 0)
116
+ continue;
117
+ const key = trimmed.slice(0, separator).trim();
118
+ const value = unquoted(trimmed.slice(separator + 1).trim());
119
+ if (value === '')
120
+ continue;
121
+ if (scope !== null && key === `${scope}:registry`)
122
+ return value;
123
+ if (key === 'registry')
124
+ fallback = value;
125
+ }
126
+ return fallback;
127
+ }
128
+ function registryOf(profileDir, pkg, manifest) {
129
+ const declared = asText(asRecord(manifest.publishConfig)?.registry);
130
+ if (declared !== '')
131
+ return declared;
132
+ const recorded = packageSourceOf(profileDir, pkg);
133
+ if (recorded !== undefined)
134
+ return recorded.registry;
135
+ const locked = registryFromLockfile(profileDir, pkg);
136
+ return locked === undefined ? registryFromNpmrc(profileDir, pkg) : locked;
137
+ }
90
138
  export function moduleDeclarationOf(profileDir, pkg) {
91
139
  if (profileDir === null || !isPackageName(pkg))
92
140
  return undefined;
@@ -144,14 +192,13 @@ export function readInstalledModule(profileDir, pkg) {
144
192
  const unit = declared === undefined ? '' : asText(declared.unit);
145
193
  if (unit === '')
146
194
  return { kind: 'not-module', pkg };
147
- const declaredRegistry = asText(asRecord(record.publishConfig)?.registry);
148
- const registry = declaredRegistry === '' ? registryFromLockfile(profileDir, pkg) : declaredRegistry;
195
+ const registry = registryOf(profileDir, pkg, record);
149
196
  return {
150
197
  kind: 'module',
151
198
  pkg,
152
199
  unit,
153
200
  version: asText(record.version),
154
- ...(registry === '' ? {} : { registry }),
201
+ ...(registry === undefined ? {} : { registry }),
155
202
  };
156
203
  }
157
204
  const PACKED_ARTIFACT = /\.(?:tgz|tar\.gz|tar)$/i;
@@ -170,6 +217,15 @@ export function isLocalDependencySpec(spec) {
170
217
  trimmed.startsWith('../') ||
171
218
  trimmed.startsWith('/'));
172
219
  }
220
+ const NON_REGISTRY_SPEC = /^(?:git\+|git:|github:|gitlab:|bitbucket:|https?:|ssh:|workspace:)/i;
221
+ export function isRegistryDependencySpec(spec) {
222
+ const trimmed = spec.trim();
223
+ if (trimmed === '')
224
+ return true;
225
+ if (isLocalDependencySpec(trimmed) || isPackedArtifactSpec(trimmed))
226
+ return false;
227
+ return !NON_REGISTRY_SPEC.test(trimmed);
228
+ }
173
229
  export function readProfilePackage(profileDir, pkg) {
174
230
  if (profileDir === null || !isPackageName(pkg))
175
231
  return undefined;
@@ -186,14 +242,13 @@ export function readProfilePackage(profileDir, pkg) {
186
242
  const version = asText(record.version);
187
243
  if (version === '')
188
244
  return undefined;
189
- const declaredRegistry = asText(asRecord(record.publishConfig)?.registry);
190
- const registry = declaredRegistry === '' ? registryFromLockfile(profileDir, pkg) : declaredRegistry;
245
+ const registry = registryOf(profileDir, pkg, record);
191
246
  const dependencies = asRecord(profileManifestOf(profileDir)?.dependencies) ?? {};
192
247
  const local = isLocalDependencySpec(asText(dependencies[pkg]));
193
248
  return {
194
249
  pkg,
195
250
  version,
196
- ...(registry === '' ? {} : { registry }),
251
+ ...(registry === undefined ? {} : { registry }),
197
252
  ...(local ? { local: true } : {}),
198
253
  };
199
254
  }
@@ -10,6 +10,5 @@ export declare function pluginToolDescription(command: PluginCommand): string;
10
10
  export declare function pluginToolWrites(command: PluginCommand): boolean;
11
11
  export declare function pluginToolSession(command: PluginCommand): OpencliSession;
12
12
  export declare function pluginToolArgv(command: PluginCommand, raw: unknown): string[];
13
- export declare function pluginKeyArgs(command: PluginCommand, raw: unknown): string;
14
- export declare function pluginApprovalQuestion(command: PluginCommand, raw: unknown): ApprovalDetail;
13
+ export declare function pluginApprovalQuestion(command: PluginCommand): ApprovalDetail;
15
14
  export declare function pluginApprovalFor(command: PluginCommand): ApprovalPolicy;
@@ -8,8 +8,6 @@ const SCHEMA_TYPE = {
8
8
  boolean: 'boolean',
9
9
  string: 'string',
10
10
  };
11
- const KEY_ARG_LIMIT = 3;
12
- const NO_KEY_ARGS = '没有带参数';
13
11
  export const RUN_CODE_TOOL = 'run_code';
14
12
  export const PLUGIN_PROMPT_BUDGET = 4_000;
15
13
  export function pluginToolName(plugin, command) {
@@ -93,35 +91,18 @@ export function pluginToolArgv(command, raw) {
93
91
  }
94
92
  return argv;
95
93
  }
96
- export function pluginKeyArgs(command, raw) {
97
- const values = valuesOf(raw);
98
- const ordered = [...command.args.filter((arg) => arg.required), ...command.args.filter((arg) => !arg.required)];
99
- const parts = [];
100
- for (const arg of ordered) {
101
- const value = values[arg.name];
102
- if (value === undefined || value === null || value === '')
103
- continue;
104
- parts.push(`${arg.name}=${String(value)}`);
105
- if (parts.length === KEY_ARG_LIMIT)
106
- break;
107
- }
108
- return parts.length === 0 ? NO_KEY_ARGS : parts.join('、');
109
- }
110
- export function pluginApprovalQuestion(command, raw) {
111
- const key = pluginKeyArgs(command, raw);
112
- const zhKey = key === NO_KEY_ARGS ? '这次没带参数' : key;
113
- const enKey = key === NO_KEY_ARGS ? 'no arguments' : key;
94
+ export function pluginApprovalQuestion(command) {
114
95
  return {
115
- zh: `agent 想执行工作台 [${command.plugin}] opencli 插件的 [${command.name}] 命令(${zhKey}),允许吗?`,
116
- en: `The agent wants to run the [${command.name}] command of the workbench opencli plugin [${command.plugin}] (${enKey}). Allow?`,
96
+ zh: `agent 想执行工作台 [${command.plugin}] opencli 插件的 [${command.name}] 命令,允许吗?`,
97
+ en: `The agent wants to run the [${command.name}] command of the workbench opencli plugin [${command.plugin}]. Allow?`,
117
98
  };
118
99
  }
119
100
  export function pluginApprovalFor(command) {
120
101
  const denied = command.access === 'read';
121
- return (call) => {
102
+ return () => {
122
103
  if (denied)
123
104
  return { kind: 'read' };
124
- const question = pluginApprovalQuestion(command, call.arguments);
105
+ const question = pluginApprovalQuestion(command);
125
106
  return {
126
107
  kind: 'ask',
127
108
  reason: command.access === 'write'
@@ -129,6 +110,7 @@ export function pluginApprovalFor(command) {
129
110
  : `${command.plugin} ${command.name} 没有拿到 access(fail-safe:按写处理)`,
130
111
  question,
131
112
  fallback: question,
113
+ noteInDetail: true,
132
114
  };
133
115
  };
134
116
  }
@@ -99,7 +99,15 @@ function faceOf(unit, opencliFor, note) {
99
99
  title: { zh: unit.plugin, en: unit.plugin },
100
100
  titleKey: unitTitleKey(unit.id),
101
101
  card: null,
102
- tools: unit.tools.map((tool) => ({ name: tool.name, writes: pluginToolWrites(tool.command) })),
102
+ tools: unit.tools.map((tool) => ({
103
+ name: tool.name,
104
+ writes: pluginToolWrites(tool.command),
105
+ opencli: {
106
+ plugin: unit.plugin,
107
+ command: tool.command.name,
108
+ args: tool.command.args.map((arg) => arg.name),
109
+ },
110
+ })),
103
111
  host: { inject: [] },
104
112
  };
105
113
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dsh-workbench/adapter-supply",
3
- "version": "1.1.4",
3
+ "version": "1.1.5",
4
4
  "description": "Workbench supply adapter package.",
5
5
  "type": "module",
6
6
  "exports": {
@@ -22,8 +22,8 @@
22
22
  "directory": "packages/adapter-supply"
23
23
  },
24
24
  "dependencies": {
25
- "@dsh-workbench/adapter-runtime": "1.1.4",
26
- "@dsh-workbench/shared": "1.1.4"
25
+ "@dsh-workbench/adapter-runtime": "1.1.5",
26
+ "@dsh-workbench/shared": "1.1.5"
27
27
  },
28
28
  "devDependencies": {
29
29
  "@types/node": "^24.19.0",