@hydranium/core 1.0.0-next.160 → 1.0.0-next.169

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.
@@ -358,13 +358,10 @@ export class DefaultModelService<
358
358
  // Deliberately NO fallback to Langium's `ready`: it resolves pre-build,
359
359
  // so falling back to it would silently reinstate the very gap this gate
360
360
  // exists to close.
361
- // Captured rather than read off `this` inside the closure, which TS cannot
362
- // prove runs after the field is assigned.
363
- const tracer = this.tracer;
364
361
  this.ready = (async () => {
365
362
  try {
366
363
  await services.workspace.WorkspaceManager?.workspaceInitialized;
367
- } catch (error: unknown) {
364
+ } catch {
368
365
  // NEVER rejects, deliberately. This gate is about TIMING — "the
369
366
  // initial build has finished" — not about whether it succeeded, and
370
367
  // Langium's `ready` (what it replaced) could not reject at all.
@@ -372,8 +369,8 @@ export class DefaultModelService<
372
369
  // build (routine — any write preempts one) and on a failed one
373
370
  // (e.g. a disposed connection at teardown). Propagating either would
374
371
  // fail every `waitForReady` for the rest of the process lifetime,
375
- // a far worse failure than the late gate this exists to fix.
376
- tracer.debug(`Initial workspace build did not complete cleanly: ${error instanceof Error ? error.message : String(error)}`);
372
+ // a far worse failure than the late gate this exists to fix. The
373
+ // workspace manager logs the outcome.
377
374
  }
378
375
  })();
379
376
  // One persistent listener mirroring non-LSP-client changes back to the LSP
@@ -922,7 +919,7 @@ export class DefaultModelService<
922
919
  try {
923
920
  let result = await this.services.workspace.TextDocuments.applyEditToLanguageClient(uri, text, { label: this.editLabel() });
924
921
  if (result?.applied === false && !this.pendingSync.has(uri)) {
925
- // The push is addressed at the client's LAST DECLARED VERSION, so a
922
+ // The push is addressed at the client's last known version, so a
926
923
  // rejection normally means the client's buffer moved while the
927
924
  // line-keyed diff was in flight — exactly the case where applying it
928
925
  // would splice the file. Dropping the push there would leave the
@@ -940,7 +937,7 @@ export class DefaultModelService<
940
937
  // `pendingSync` check skips the retry when a newer settle has already
941
938
  // queued — best-effort, since a settle arriving later simply pushes
942
939
  // after this and still wins.
943
- uriLogger.warn(`Language client rejected applyEdit at its declared version — re-pushing a full replace`);
940
+ uriLogger.debug(`Re-pushing a full replace after the language client refused applyEdit`);
944
941
  result = await this.services.workspace.TextDocuments.applyEditToLanguageClient(uri, text, { label: this.editLabel() });
945
942
  if (result?.applied === false) {
946
943
  uriLogger.warn(`Language client rejected the full-replace retry too — client content is stale`);
@@ -8,7 +8,15 @@
8
8
  ********************************************************************************/
9
9
 
10
10
  import { Deferred, type Logger, type Tracer } from '@hydranium/protocol';
11
- import { DefaultWorkspaceManager, DocumentState, type LangiumDocument, type Stream, UriUtils, type URI } from '@hydranium/langium';
11
+ import {
12
+ DefaultWorkspaceManager,
13
+ DocumentState,
14
+ isOperationCancelled,
15
+ type LangiumDocument,
16
+ type Stream,
17
+ UriUtils,
18
+ type URI
19
+ } from '@hydranium/langium';
12
20
  import { type CancellationToken, type InitializeParams } from 'vscode-languageserver';
13
21
  import type { WorkspaceFolder } from 'vscode-languageserver-types';
14
22
  import { type LogNameOptions, resolveLogFilePlaceholder, toLogFileWorkspaceToken } from '../diagnostics/logger.js';
@@ -20,6 +28,7 @@ import type { WritableFileSystemProvider } from '../../documents/ast-document-ma
20
28
  import { type DocumentUriPolicy, findRealpathDivergence } from './document-uri-policy.js';
21
29
  import { type AdditionalDocumentContribution, collectAdditionalDocuments } from './additional-document-contribution.js';
22
30
  import { onProcessEvent } from '../../util/environment.js';
31
+ import { isConnectionGoneError } from '../../util/connection-liveness.js';
23
32
 
24
33
  /**
25
34
  * Module-level guard so repeated workspace-manager construction (e.g.
@@ -488,12 +497,22 @@ export class HydraniumWorkspaceManager extends DefaultWorkspaceManager {
488
497
  * and either delegate to `super.initializeWorkspace(...)` (preserving the
489
498
  * default resolve) or call `this.workspaceInitializedDeferred.resolve(...)`
490
499
  * themselves after the additional work finishes.
500
+ *
501
+ * A failed setup is logged here, since every framework waiter on
502
+ * {@link workspaceInitialized} discards the rejection; an override that
503
+ * rejects the deferred itself logs its own failure.
491
504
  */
492
505
  override async initializeWorkspace(folders: WorkspaceFolder[], cancelToken?: CancellationToken): Promise<void> {
493
506
  try {
494
507
  await super.initializeWorkspace(folders, cancelToken);
495
508
  this.workspaceInitializedDeferred.resolve(undefined);
496
- } catch (error) {
509
+ } catch (error: unknown) {
510
+ const message = error instanceof Error ? error.message : String(error);
511
+ if (isOperationCancelled(error) || isConnectionGoneError(error)) {
512
+ this.tracer.debug(`Initial workspace build did not complete: ${message}`);
513
+ } else {
514
+ this.tracer.error(`Initial workspace build failed: ${message}`);
515
+ }
497
516
  this.workspaceInitializedDeferred.reject(error);
498
517
  throw error;
499
518
  }