@deepseek-ai/dsh-experimental-forge 0.2.2-alpha.2 → 0.2.2-alpha.3

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.
package/README.i18n.yaml CHANGED
@@ -15,8 +15,8 @@
15
15
  en: d152484eb41ac6b4
16
16
  zh: 2f8a621b991260a1
17
17
  /deepseek-ai-dsh-experimental-forge/use-this-package:
18
- en: 5f4f14ee9aad5072
19
- zh: 6c8606796df24a3e
18
+ en: 9ca86ee541048ff2
19
+ zh: 7aef4feb76542dd6
20
20
  /deepseek-ai-dsh-experimental-forge/understand-the-implementation:
21
21
  en: e193cb547c47069b
22
22
  zh: faa517522402ea41
package/README.md CHANGED
@@ -38,10 +38,14 @@ Mount the registry with at least one provider package, such as the GitHub provid
38
38
 
39
39
  `diff(ref, signal)` reads the change request's unified patch as the host computes it, with `a/` and `b/` path prefixes, and `fileText(ref, commit, path, signal)` reads one file of its repository at a commit. Both delegate to the provider of the reference's forge, throw when none is registered, and resolve to the text or to a `ForgeFailure`, which is `too-large` when the host or the provider refuses an answer over its size limit. `fileUrl(ref, commit, path)` returns the web page of that file at that commit.
40
40
 
41
- `ctx.forge.watch(ref, listener)` is also an effect. The first watcher of a change request polls it at once; `latest(ref)` returns the most recent result. Each forge has at most one fetch in flight, and that fetch includes every due change request of the forge. An open change request is polled every `activeIntervalMs` while checks are pending or mergeability is unknown, and every `idleIntervalMs` otherwise. Closed change requests use `idleIntervalMs` to detect reopening; merged requests stop automatic polling. `refresh(ref)` polls a watched change request at once, including after a terminal state; if a fetch is already in flight for its forge, another fetch starts immediately after it settles. A failed read repeats after `activeIntervalMs` doubled for each consecutive failure, up to `maxBackoffMs`, which must be at least `activeIntervalMs`. Unregistering a provider settles its watched change requests as `unavailable`. Polling stops when the last watcher leaves. The [configuration catalog](../../../docs/config-catalog.md#deepseek-aidsh-experimental-forge) lists the defaults.
41
+ `fetchChecks(ref, signal)` reads one change request’s complete checks on demand. It has its own `fetchTimeoutMs` deadline and does not occupy the polling batch or publish to its watchers. Failure leaves previously polled snapshots intact. A provider without `fetchChecks` returns `unavailable`. Caller cancellation and provider or service disposal abort the read; disposal waits for it to settle.
42
+
43
+ `ctx.forge.watch(ref, listener)` is also an effect. The first watcher of a change request polls it at once; `latest(ref)` returns the most recent result. Each forge has at most one polling fetch in flight, and that fetch includes every due change request of the forge. An open change request is polled every `activeIntervalMs` while checks are pending or mergeability is unknown, and every `idleIntervalMs` otherwise. Closed change requests use `idleIntervalMs` to detect reopening; merged requests stop automatic polling. `refresh(ref)` polls a watched change request at once, including after a terminal state; if a fetch is already in flight for its forge, another fetch starts immediately after it settles. A failed read repeats after `activeIntervalMs` doubled for each consecutive failure, up to `maxBackoffMs`, which must be at least `activeIntervalMs`. Unregistering a provider settles its watched change requests as `unavailable`. Polling stops when the last watcher leaves. The [configuration catalog](../../../docs/config-catalog.md#deepseek-aidsh-experimental-forge) lists the defaults.
42
44
 
43
45
  Reaching `fetchTimeoutMs` aborts the fetch signal with `FORGE_FETCH_TIMEOUT`. Providers must stop their work and settle when the signal aborts; rejected fetches become `unavailable` failures. A provider that ignores cancellation can stall polling and service disposal.
44
46
 
47
+ Providers may implement `submitReview` to publish a line comment or a completed review at an explicit head commit. The registry returns unsupported when that capability is absent and refreshes watched status after a submission. Successful writes return their web URL; failures distinguish changed heads, refusals, and unknown outcomes. Callers must reconcile unknown outcomes before another submission. Pending drafts belong to the consumer, not the polling registry.
48
+
45
49
  -----
46
50
 
47
51
  <a id="understand-the-implementation"></a>
package/README.zh.md CHANGED
@@ -38,10 +38,14 @@ kind: "package-reference"
38
38
 
39
39
  `diff(ref, signal)` 读取托管平台计算出的变更请求统一补丁,路径带 `a/` 与 `b/` 前缀;`fileText(ref, commit, path, signal)` 读取其仓库中某个提交下的一个文件。两者都委托给引用所属 forge 的提供方,没有注册提供方时抛错,resolve 为文本或 `ForgeFailure`;托管平台或提供方因结果超过其大小上限而拒绝时,失败为 `too-large`。`fileUrl(ref, commit, path)` 返回该文件在该提交下的网页地址。
40
40
 
41
- `ctx.forge.watch(ref, listener)` 同样是 effect。变更请求的第一个监听方会立即触发轮询;`latest(ref)` 返回最近一次结果。每个 forge 同时最多只有一次读取在进行,这次读取包含该 forge 所有到期的变更请求。打开状态的变更请求在检查未完成或可合并性未知时每 `activeIntervalMs` 轮询一次,否则每 `idleIntervalMs` 轮询一次。已关闭的变更请求按 `idleIntervalMs` 轮询以检测重新打开;已合并的停止自动轮询。`refresh(ref)` 立即轮询一个被监听的变更请求,已结束的也包括在内;该 forge 已有读取在进行时,等待其结束后立即再读一次。读取失败后,重试间隔为 `activeIntervalMs` 按连续失败次数翻倍,最长 `maxBackoffMs`;该值必须大于或等于 `activeIntervalMs`。注销提供方会让其被监听的变更请求以 `unavailable` 结束。最后一个监听方离开后轮询停止。默认值见[配置目录](../../../docs/config-catalog.zh.md#deepseek-aidsh-experimental-forge)。
41
+ `fetchChecks(ref, signal)` 按需读取单个变更请求的完整检查,使用独立的 `fetchTimeoutMs` 时限,不占用轮询批次,也不向其监听方发布结果。读取失败时保留已有轮询快照。提供方未实现 `fetchChecks` 时返回 `unavailable`。调用方取消、提供方或服务销毁都会中止读取;销毁会等待读取结束。
42
+
43
+ `ctx.forge.watch(ref, listener)` 同样是 effect。变更请求的第一个监听方会立即触发轮询;`latest(ref)` 返回最近一次结果。每个 forge 同时最多只有一次轮询读取在进行,这次读取包含该 forge 所有到期的变更请求。打开状态的变更请求在检查未完成或可合并性未知时每 `activeIntervalMs` 轮询一次,否则每 `idleIntervalMs` 轮询一次。已关闭的变更请求按 `idleIntervalMs` 轮询以检测重新打开;已合并的停止自动轮询。`refresh(ref)` 立即轮询一个被监听的变更请求,已结束的也包括在内;该 forge 已有读取在进行时,等待其结束后立即再读一次。读取失败后,重试间隔为 `activeIntervalMs` 按连续失败次数翻倍,最长 `maxBackoffMs`;该值必须大于或等于 `activeIntervalMs`。注销提供方会让其被监听的变更请求以 `unavailable` 结束。最后一个监听方离开后轮询停止。默认值见[配置目录](../../../docs/config-catalog.zh.md#deepseek-aidsh-experimental-forge)。
42
44
 
43
45
  达到 `fetchTimeoutMs` 时,读取信号会以 `FORGE_FETCH_TIMEOUT` 中止。提供方必须在信号中止时停止工作并结束请求;被拒绝的读取会转为 `unavailable` 失败。忽略取消的提供方可能阻塞轮询和服务销毁。
44
46
 
47
+ provider 可以实现 `submitReview`,在指定的 head 提交上发布行内评论或完整评审。未实现该能力时,注册表返回不支持;提交结束后会刷新受关注的状态。成功的写操作返回网页 URL;失败区分 head 变化、明确拒绝与结果不明。调用方必须先核对结果不明的操作,再次提交。待提交草稿由消费者管理,不由轮询注册表保存。
48
+
45
49
  -----
46
50
 
47
51
  <a id="understand-the-implementation"></a>
package/lib/index.js CHANGED
@@ -255,6 +255,32 @@ var ForgeService = class extends Service {
255
255
  return failure;
256
256
  }
257
257
  /**
258
+ * Read complete check details independently of periodic polling.
259
+ * @param ref - change request served by a registered provider.
260
+ * @param signal - cancellation of the detail view.
261
+ * @returns a complete snapshot or the provider's failure; unsupported providers return unavailable.
262
+ * @throws on cancellation, provider disposal, or expiry of this read's own `fetchTimeoutMs` deadline.
263
+ */
264
+ async fetchChecks(ref, signal) {
265
+ const env_1 = {
266
+ stack: [],
267
+ error: void 0,
268
+ hasError: false
269
+ };
270
+ try {
271
+ const timeout = __addDisposableResource(env_1, deadline(signal, this.config.fetchTimeoutMs, "FORGE_FETCH_TIMEOUT"), false);
272
+ return await this.invoke(this.registration(ref.repository.forge), timeout.signal, (provider, operation) => provider.fetchChecks?.(ref, operation) ?? Promise.resolve({
273
+ code: "unavailable",
274
+ message: "This provider does not support complete check reads"
275
+ }));
276
+ } catch (e_1) {
277
+ env_1.error = e_1;
278
+ env_1.hasError = true;
279
+ } finally {
280
+ __disposeResources(env_1);
281
+ }
282
+ }
283
+ /**
258
284
  * Read the changes of a change request as its host computes them.
259
285
  * @param ref - change request served by a registered provider.
260
286
  * @param signal - cancellation of the read.
@@ -265,6 +291,22 @@ var ForgeService = class extends Service {
265
291
  return await this.invoke(this.registration(ref.repository.forge), signal, (provider, operation) => provider.diff(ref, operation));
266
292
  }
267
293
  /**
294
+ * Publish one comment or a completed review, then refresh the watched status.
295
+ * @param ref - change request served by a registered provider.
296
+ * @param request - explicitly selected commit, comments, and review decision.
297
+ * @param signal - request cancellation.
298
+ * @returns a publication URL or a failure, including an unknown write outcome.
299
+ */
300
+ async submitReview(ref, request, signal) {
301
+ const result = await this.invoke(this.registration(ref.repository.forge), signal, (provider, operation) => provider.submitReview?.(ref, request, operation) ?? Promise.resolve({
302
+ ok: false,
303
+ code: "unsupported",
304
+ message: "This provider does not support review submission"
305
+ }));
306
+ this.refresh(ref);
307
+ return result;
308
+ }
309
+ /**
268
310
  * Read the text of one file at a commit of a change request's repository.
269
311
  * @param ref - change request served by a registered provider.
270
312
  * @param commit - commit object name.
@@ -425,19 +467,19 @@ var ForgeService = class extends Service {
425
467
  try {
426
468
  if (registration === void 0) failure = this.missing(forge);
427
469
  else {
428
- const env_1 = {
470
+ const env_2 = {
429
471
  stack: [],
430
472
  error: void 0,
431
473
  hasError: false
432
474
  };
433
475
  try {
434
- const timeout = __addDisposableResource(env_1, deadline(this.lifetime.signal, this.config.fetchTimeoutMs, "FORGE_FETCH_TIMEOUT"), false);
476
+ const timeout = __addDisposableResource(env_2, deadline(this.lifetime.signal, this.config.fetchTimeoutMs, "FORGE_FETCH_TIMEOUT"), false);
435
477
  results = await this.invoke(registration, timeout.signal, (provider, operation) => provider.fetch(batch.map((watch) => watch.ref), operation));
436
- } catch (e_1) {
437
- env_1.error = e_1;
438
- env_1.hasError = true;
478
+ } catch (e_2) {
479
+ env_2.error = e_2;
480
+ env_2.hasError = true;
439
481
  } finally {
440
- __disposeResources(env_1);
482
+ __disposeResources(env_2);
441
483
  }
442
484
  }
443
485
  } catch (error) {
@@ -1,7 +1,7 @@
1
1
  /** Registry of code-host providers with provider-neutral change requests and shared status polling. */
2
2
  import { Context, Service } from '@deepseek-ai/cordis';
3
3
  import z from '@deepseek-ai/schemastery';
4
- import type { ChangeRequestListener, ChangeRequestRef, ChangeRequestUpdate, Config, ForgeActionFailure, ForgeFailure, ForgeProvider, ForgeReadiness, ForgeRepository, MergeRequest } from './types.ts';
4
+ import type { ChangeRequestListener, ChangeRequestRef, ChangeRequestSnapshot, ChangeRequestUpdate, Config, ForgeActionFailure, ForgeFailure, ForgeProvider, ForgeReadiness, ForgeRepository, ForgeReviewRequest, ForgeReviewResult, MergeRequest } from './types.ts';
5
5
  export { changeRequestKey } from './keys.ts';
6
6
  export type * from './types.ts';
7
7
  declare module '@deepseek-ai/cordis' {
@@ -104,6 +104,14 @@ export declare class ForgeService extends Service {
104
104
  * @throws when no provider serves the change request's forge, or with `signal.reason` when it aborts.
105
105
  */
106
106
  merge(ref: ChangeRequestRef, request: MergeRequest, signal: AbortSignal): Promise<ForgeActionFailure | undefined>;
107
+ /**
108
+ * Read complete check details independently of periodic polling.
109
+ * @param ref - change request served by a registered provider.
110
+ * @param signal - cancellation of the detail view.
111
+ * @returns a complete snapshot or the provider's failure; unsupported providers return unavailable.
112
+ * @throws on cancellation, provider disposal, or expiry of this read's own `fetchTimeoutMs` deadline.
113
+ */
114
+ fetchChecks(ref: ChangeRequestRef, signal: AbortSignal): Promise<ChangeRequestSnapshot | ForgeFailure>;
107
115
  /**
108
116
  * Read the changes of a change request as its host computes them.
109
117
  * @param ref - change request served by a registered provider.
@@ -112,6 +120,14 @@ export declare class ForgeService extends Service {
112
120
  * @throws when no provider serves the change request's forge, or with `signal.reason` when it aborts.
113
121
  */
114
122
  diff(ref: ChangeRequestRef, signal: AbortSignal): Promise<string | ForgeFailure>;
123
+ /**
124
+ * Publish one comment or a completed review, then refresh the watched status.
125
+ * @param ref - change request served by a registered provider.
126
+ * @param request - explicitly selected commit, comments, and review decision.
127
+ * @param signal - request cancellation.
128
+ * @returns a publication URL or a failure, including an unknown write outcome.
129
+ */
130
+ submitReview(ref: ChangeRequestRef, request: ForgeReviewRequest, signal: AbortSignal): Promise<ForgeReviewResult>;
115
131
  /**
116
132
  * Read the text of one file at a commit of a change request's repository.
117
133
  * @param ref - change request served by a registered provider.
@@ -126,6 +126,36 @@ export interface MergeRequest {
126
126
  /** Commit object name the head must still have; the merge is refused once the head moves. */
127
127
  readonly headSha: string;
128
128
  }
129
+ /** One inline comment addressed to the old or new side of a pull request diff. */
130
+ export interface ForgeLineComment {
131
+ readonly path: string;
132
+ readonly side: 'L' | 'R';
133
+ readonly startLine: number;
134
+ readonly endLine: number;
135
+ readonly body: string;
136
+ }
137
+ /** A single published comment or one completed review containing all pending comments. */
138
+ export type ForgeReviewRequest = {
139
+ /** Commit the user reviewed; providers must check it before writing and address that commit explicitly. */
140
+ readonly headSha: string;
141
+ } & ({
142
+ readonly kind: 'comment';
143
+ readonly comment: ForgeLineComment;
144
+ } | {
145
+ readonly kind: 'review';
146
+ readonly event: 'comment' | 'approve' | 'request-changes';
147
+ readonly body: string;
148
+ readonly comments: readonly ForgeLineComment[];
149
+ });
150
+ /** Result of a review write; unknown outcomes must be checked on the host before another submission. */
151
+ export type ForgeReviewResult = {
152
+ readonly ok: true;
153
+ readonly url: string;
154
+ } | {
155
+ readonly ok: false;
156
+ readonly code: 'unsupported' | 'stale' | 'failed' | 'unknown';
157
+ readonly message: string;
158
+ };
129
159
  /** Why a provider could not change a change request. */
130
160
  export interface ForgeActionFailure {
131
161
  /**
@@ -150,6 +180,8 @@ export interface ForgeReadiness {
150
180
  export interface ForgeProvider {
151
181
  /** Forge family name stored in every repository this provider returns. */
152
182
  readonly forge: string;
183
+ /** Publish a comment or completed review. Omission declares that this provider cannot write reviews. */
184
+ submitReview?(ref: ChangeRequestRef, request: ForgeReviewRequest, signal: AbortSignal): Promise<ForgeReviewResult>;
153
185
  /** Map a Git remote URL to its repository, or undefined when this provider does not serve it. */
154
186
  repositoryFromRemote(url: string): ForgeRepository | undefined;
155
187
  /** Map a change request web URL to its reference, or undefined when this provider does not serve it. */
@@ -158,6 +190,8 @@ export interface ForgeProvider {
158
190
  changeRequestUrl(ref: ChangeRequestRef): string;
159
191
  /** Read the status of several change requests, returning one result per requested key. */
160
192
  fetch(refs: readonly ChangeRequestRef[], signal: AbortSignal): Promise<ReadonlyMap<ChangeRequestKey, ChangeRequestSnapshot | ForgeFailure>>;
193
+ /** Read all checks for one change request on demand; omission declares that only the polling preview is available. */
194
+ fetchChecks?(ref: ChangeRequestRef, signal: AbortSignal): Promise<ChangeRequestSnapshot | ForgeFailure>;
161
195
  /** Find open change requests whose head is `branch` in `repository`, excluding the default branch and forks. */
162
196
  findByHead(repository: ForgeRepository, branch: string, signal: AbortSignal): Promise<readonly ChangeRequestRef[]>;
163
197
  /** Report whether the provider can reach `host` with current credentials. */
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@deepseek-ai/dsh-experimental-forge",
3
3
  "description": "Provider-neutral change request registry with shared status polling",
4
- "version": "0.2.2-alpha.2",
4
+ "version": "0.2.2-alpha.3",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -32,14 +32,14 @@
32
32
  "directory": "packages/experimental/forge"
33
33
  },
34
34
  "dependencies": {
35
- "@deepseek-ai/schemastery": "~3.18.6-alpha.1",
36
- "@deepseek-ai/dsh-brand": "0.2.2-alpha.2",
37
- "@deepseek-ai/dsh-timeout": "0.2.2-alpha.2"
35
+ "@deepseek-ai/schemastery": "~3.18.6-alpha.2",
36
+ "@deepseek-ai/dsh-brand": "0.2.2-alpha.3",
37
+ "@deepseek-ai/dsh-timeout": "0.2.2-alpha.3"
38
38
  },
39
39
  "peerDependencies": {
40
- "@deepseek-ai/cordis": "~4.0.6-alpha.1"
40
+ "@deepseek-ai/cordis": "~4.0.6-alpha.2"
41
41
  },
42
42
  "devDependencies": {
43
- "@deepseek-ai/cordis": "~4.0.6-alpha.1"
43
+ "@deepseek-ai/cordis": "~4.0.6-alpha.2"
44
44
  }
45
45
  }