Files
Yishen Tu 9c4d92f638 feat: add Claudian Collab mode (#1117)
* feat(collab): establish shared protocol and core contracts

* feat(collab): implement LAN collaboration services

* feat(collab): add agent runtime and provider integration

* feat(collab): add collaboration user interface

* feat(chat): add linked content and Collab references

* feat(collab): wire plugin lifecycle and build tooling

* test(collab): cover collaboration workflows

* docs(collab): document collaboration architecture

* fix: support locked Obsidian types in settings

* fix: build protocol before linting

* test: make Collab suites portable in CI

* fix: isolate conflict merge identity

* fix(collab): harden protocol and Git portability

* ci: harden cross-platform and protocol verification

* ci: make release workflow shell-safe

* fix(collab): make Windows Git smoke portable

* test(collab): expose safe Git smoke diagnostics

* fix(collab): bind receive hook Git through PATH

* test(collab): surface receive-pack failure context

* test(collab): label Git HTTP failure stages

* fix(collab): trust LAN CA with Windows Schannel

* fix(collab): summarize Git failures safely

* fix(collab): skip CRL checks for pinned LAN CA

* fix(collab): select Schannel for Windows LAN Git

* chore: scope cross-platform smoke to relevant PRs

* fix: reopen reviews from expanded file rows

* test: keep Collab style check compatible with target

* refactor: enforce collab state ownership and bounded reads

* refactor: harden collab lifecycle and state ownership

* fix: reconnect Collab members from stale endpoints
2026-08-20 22:55:25 +08:00

167 lines
5.3 KiB
TypeScript

import { TextDecoder, TextEncoder } from 'node:util';
type TestWindow = typeof globalThis & {
cancelAnimationFrame?: (handle: number) => void;
requestAnimationFrame?: (callback: FrameRequestCallback) => number;
};
const testWindow = globalThis as TestWindow;
if (!globalThis.TextEncoder) {
Object.assign(globalThis, { TextDecoder, TextEncoder });
}
if (!testWindow.requestAnimationFrame) {
testWindow.requestAnimationFrame = (callback: FrameRequestCallback): number => (
Number(setTimeout(() => callback(Date.now()), 0))
);
}
if (!testWindow.cancelAnimationFrame) {
testWindow.cancelAnimationFrame = (handle: number): void => {
clearTimeout(handle);
};
}
if (globalThis.Range && !Reflect.has(globalThis.Range.prototype, 'getClientRects')) {
Object.defineProperty(globalThis.Range.prototype, 'getClientRects', {
configurable: true,
value: () => [],
});
}
if (!('window' in globalThis)) {
Object.defineProperty(globalThis, 'window', {
configurable: true,
value: testWindow,
writable: true,
});
}
// Polyfill Obsidian DOM helpers for jsdom-based tests.
const SVG_NS = 'http://www.w3.org/2000/svg';
function applyDomElementInfo(el: Element, info: unknown): void {
if (!info) return;
if (typeof info === 'string') {
el.classList.add(...info.split(/\s+/).filter(Boolean));
return;
}
const opts = info as Record<string, unknown>;
if (opts.cls) {
const classes = Array.isArray(opts.cls) ? opts.cls : String(opts.cls).split(/\s+/);
el.classList.add(...classes.filter(Boolean) as string[]);
}
if (opts.text && 'textContent' in el) {
(el as HTMLElement).textContent = String(opts.text);
}
if (opts.attr) {
for (const [key, value] of Object.entries(opts.attr as Record<string, unknown>)) {
if (value === null || value === undefined) continue;
el.setAttribute(key, String(value));
}
}
if (opts.title && 'setAttribute' in el) {
el.setAttribute('title', String(opts.title));
}
}
(globalThis as typeof globalThis & { createDiv?: typeof createDiv }).createDiv = function createDiv(
info?: unknown,
callback?: (el: HTMLDivElement) => void,
): HTMLDivElement {
const el = document.createElement('div');
applyDomElementInfo(el, info);
if (callback) callback(el);
return el;
};
(globalThis as typeof globalThis & { createEl?: typeof createEl }).createEl = function createEl<K extends keyof HTMLElementTagNameMap>(
tag: K,
info?: unknown,
callback?: (el: HTMLElementTagNameMap[K]) => void,
): HTMLElementTagNameMap[K] {
const el = document.createElement(tag);
applyDomElementInfo(el, info);
if (callback) callback(el);
return el;
};
(globalThis as typeof globalThis & { createSpan?: typeof createSpan }).createSpan = function createSpan(
info?: unknown,
callback?: (el: HTMLSpanElement) => void,
): HTMLSpanElement {
const el = document.createElement('span');
applyDomElementInfo(el, info);
if (callback) callback(el);
return el;
};
(globalThis as typeof globalThis & { createSvg?: typeof createSvg }).createSvg = function createSvg<K extends keyof SVGElementTagNameMap>(
tag: K,
info?: unknown,
callback?: (el: SVGElementTagNameMap[K]) => void,
): SVGElementTagNameMap[K] {
const el = document.createElementNS(SVG_NS, tag) as SVGElementTagNameMap[K];
applyDomElementInfo(el, info);
if (callback) callback(el);
return el;
};
(globalThis as typeof globalThis & { createFragment?: typeof createFragment }).createFragment = function createFragment(
callback?: (el: DocumentFragment) => void,
): DocumentFragment {
const el = document.createDocumentFragment();
if (callback) callback(el);
return el;
};
if (globalThis.Node && !Reflect.has(globalThis.Node.prototype, 'win')) {
Object.defineProperty(globalThis.Node.prototype, 'win', {
configurable: true,
get(this: Node): Window {
const owner = this.nodeType === Node.DOCUMENT_NODE
? this as Document
: this.ownerDocument;
return owner?.defaultView ?? globalThis.window;
},
});
}
if (globalThis.HTMLElement && !Reflect.has(globalThis.HTMLElement.prototype, 'createDiv')) {
globalThis.HTMLElement.prototype.createDiv = function (this: HTMLElement, info?, callback?) {
const el = createDiv(info, callback);
this.appendChild(el);
return el;
};
globalThis.HTMLElement.prototype.createEl = function (this: HTMLElement, tag, info?, callback?) {
const el = createEl(tag, info, callback);
this.appendChild(el);
return el;
};
globalThis.HTMLElement.prototype.createSpan = function (this: HTMLElement, info?, callback?) {
const el = createSpan(info, callback);
this.appendChild(el);
return el;
};
globalThis.HTMLElement.prototype.createSvg = function (this: HTMLElement, tag, info?, callback?) {
const el = createSvg(tag, info, callback);
this.appendChild(el);
return el;
};
}
if (globalThis.HTMLElement && !Reflect.has(globalThis.HTMLElement.prototype, 'setText')) {
globalThis.HTMLElement.prototype.setText = function (this: HTMLElement, value: string) {
this.textContent = value;
};
}
if (globalThis.SVGElement && !Reflect.has(globalThis.SVGElement.prototype, 'createSvg')) {
globalThis.SVGElement.prototype.createSvg = function (this: SVGElement, tag, info?, callback?) {
const el = createSvg(tag, info, callback);
this.appendChild(el);
return el;
};
}