@withgraphite/graphite-cli 1.0.6 → 1.0.7
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/.CHANGELOG.md +10 -0
- package/325.js +1 -1
- package/325.js.map +1 -1
- package/child.js.map +1 -1
- package/graphite.js +1 -1
- package/package.json +1 -1
package/325.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"325.js","mappings":"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","sources":["webpack://@withgraphite/graphite-cli/../../src/Comparison.ts","webpack://@withgraphite/graphite-cli/../../src/LRU.ts","webpack://@withgraphite/graphite-cli/../../../src/analytics/index.ts","webpack://@withgraphite/graphite-cli/../../../src/analytics/tracker.ts","webpack://@withgraphite/graphite-cli/../../src/compat.ts","webpack://@withgraphite/graphite-cli/../../src/debounce.ts","webpack://@withgraphite/graphite-cli/../../src/immutableExt.ts","webpack://@withgraphite/graphite-cli/../../src/index.ts","webpack://@withgraphite/graphite-cli/../../src/minimalDisambiguousPaths.ts","webpack://@withgraphite/graphite-cli/../../../src/patch/parse.ts","webpack://@withgraphite/graphite-cli/../../src/serialize.ts","webpack://@withgraphite/graphite-cli/../../../src/types/client.ts","webpack://@withgraphite/graphite-cli/../../../src/types/constants.ts","webpack://@withgraphite/graphite-cli/../../../src/types/index.ts","webpack://@withgraphite/graphite-cli/../../src/utils.ts","webpack://@withgraphite/graphite-cli/../gti-server/src/analytics/environment.ts","webpack://@withgraphite/graphite-cli/../gti-server/src/analytics/serverSideTracker.ts","webpack://@withgraphite/graphite-cli/../gti-server/src/logger.ts","webpack://@withgraphite/graphite-cli/../gti-server/src/TypedEventEmitter.ts","webpack://@withgraphite/graphite-cli/../gti-server/src/github/githubCodeReviewProvider.ts","webpack://@withgraphite/graphite-cli/../gti-server/src/OperationQueue.ts","webpack://@withgraphite/graphite-cli/../gti-server/src/PageFocusTracker.ts","webpack://@withgraphite/graphite-cli/../gti-server/src/RateLimiter.ts","webpack://@withgraphite/graphite-cli/../gti-server/src/utils.ts","webpack://@withgraphite/graphite-cli/../gti-server/src/watchman.ts","webpack://@withgraphite/graphite-cli/../gti-server/src/WatchForChanges.ts","webpack://@withgraphite/graphite-cli/../gti-server/src/Repository.ts","webpack://@withgraphite/graphite-cli/../gti-server/src/fs.ts","webpack://@withgraphite/graphite-cli/../gti-server/src/serverPlatform.ts","webpack://@withgraphite/graphite-cli/../gti-server/src/RepositoryCache.ts","webpack://@withgraphite/graphite-cli/../gti-server/src/ServerToClientAPI.ts","webpack://@withgraphite/graphite-cli/../gti-server/proxy/existingServerStateFiles.ts","webpack://@withgraphite/graphite-cli/../gti-server/proxy/proxyUtils.ts","webpack://@withgraphite/graphite-cli/../gti-server/src/index.ts","webpack://@withgraphite/graphite-cli/../gti-server/proxy/server.ts"],"sourcesContent":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,"import type { ApplicationInfo } from \"@withgraphite/gti-shared\";\nimport { randomId, unwrap } from \"@withgraphite/gti-shared\";\nimport os from \"os\";\n\nexport function getUsername(): string {\n try {\n return os.userInfo().username;\n } catch (osInfoError) {\n try {\n const { env } = process;\n return unwrap(env.LOGNAME || env.USER || env.LNAME || env.USERNAME);\n } catch (processEnvError) {\n throw new Error(String(processEnvError) + String(osInfoError));\n }\n }\n}\n\nexport function generateAnalyticsInfo(\n platformName: string,\n version: string\n): ApplicationInfo {\n return {\n platform: platformName,\n version,\n repo: undefined,\n /**\n * Random id for this GTI session, created at startup.\n * Note: this is only generated on the server, so client-logged events share the ID with the server.\n */\n sessionId: randomId(),\n unixname: getUsername(),\n osArch: os.arch(),\n osType: os.platform(),\n osRelease: os.release(),\n hostname: os.hostname(),\n };\n}\n","import type {\n ApplicationInfo,\n FullTrackData,\n Logger,\n TrackDataWithEventName,\n} from \"@withgraphite/gti-shared\";\nimport { Tracker } from \"@withgraphite/gti-shared\";\n\nimport type { Repository } from \"../Repository\";\nimport type { ServerPlatform } from \"../serverPlatform\";\nimport { generateAnalyticsInfo } from \"./environment\";\n\nexport type ServerSideTracker = Tracker<ServerSideContext>;\n\nclass ServerSideContext {\n constructor(public logger: Logger, public data: ApplicationInfo) {}\n\n public setRepo(repo: Repository | undefined): void {\n this.data.repo = repo?.codeReviewProvider?.getSummaryName();\n }\n}\n\nconst noOp = (_data: FullTrackData): Promise<unknown> | void => {\n /* In open source builds, analytics tracking is completely disabled/removed. */\n};\n\n/**\n * Creates a Tracker which includes server-side-only cached application data like platform, username, etc,\n * and sends data to the underlying analytics engine outside of GTI.\n * This can not be global since two client connections may have different cached data.\n */\nexport function makeServerSideTracker(\n logger: Logger,\n platform: ServerPlatform,\n version: string,\n // prettier-ignore\n writeToServer = noOp\n): ServerSideTracker {\n return new Tracker(\n (data: TrackDataWithEventName, context: ServerSideContext) => {\n const { logger } = context;\n // log track event, since tracking events can be used as datapoints when reviewing logs\n logger.log(\n \"[track]\",\n data.eventName,\n data.errorName ?? \"\",\n data.errorMessage ?? \"\",\n data.extras != null ? JSON.stringify(data.extras) : \"\"\n );\n try {\n Promise.resolve(writeToServer({ ...data, ...context.data })).catch(\n (err) => void err\n );\n } catch {\n // pass\n }\n },\n new ServerSideContext(\n logger,\n generateAnalyticsInfo(platform.platformName, version)\n )\n );\n}\n","import type { Logger } from \"@withgraphite/gti-shared\";\nimport fs from \"fs\";\nimport util from \"util\";\n\nexport const stdoutLogger = console;\n\nexport function fileLogger(filename: string): Logger {\n const log = (...args: Parameters<typeof console.log>) => {\n const str = util.format(...args) + \"\\n\";\n void fs.promises.appendFile(filename, str);\n };\n\n return {\n info: log,\n log,\n warn: log,\n error: log,\n\n getLogFileContents: () => {\n return fs.promises.readFile(filename, \"utf-8\");\n },\n };\n}\n","import { EventEmitter } from \"events\";\n\n/**\n * Like {@link EventEmitter}, but with type checking for one particular subscription type,\n * plus errors.\n * ```\n * const myEmitter = new TypedEventEmitter<'data', number>();\n * myEmitter.on('data', (data: number) => ...); // typechecks 'data' param and callback\n * myEmitter.on('error', (error: Error) => ...); // errors are always allowed too\n * // Fields other than 'data' and 'error' are type errors.\n * ```\n */\nexport declare interface TypedEventEmitter<\n EventName extends string,\n EventType\n> {\n on(event: EventName, listener: (data: EventType) => void): this;\n on(event: \"error\", listener: (error: Error) => void): this;\n off(event: EventName, listener: (data: EventType) => void): this;\n off(event: \"error\", listener: (error: Error) => void): this;\n\n emit(\n ...args: EventType extends undefined\n ? [event: EventName] | [event: EventName, data: EventType]\n : [event: EventName, data: EventType]\n ): boolean;\n emit(event: \"error\", error: Error): boolean;\n}\n\nexport class TypedEventEmitter<\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n EventName extends string,\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n EventType\n> extends EventEmitter {}\n","import type { PRInfo, PRNumber } from \"@withgraphite/gti-cli-shared-types\";\nimport type {\n CodeReviewSystem,\n Disposable,\n GitHubDiffSummary,\n OperationCommandProgressReporter,\n Result,\n TypeaheadKind,\n TypeaheadResult,\n} from \"@withgraphite/gti-shared\";\nimport type execa from \"execa\";\n\nimport { TypedEventEmitter } from \"../TypedEventEmitter\";\n\ntype GitHubCodeReviewSystem = CodeReviewSystem & { type: \"github\" };\nexport class GitHubCodeReviewProvider {\n constructor(\n private codeReviewSystem: GitHubCodeReviewSystem,\n private runCommand: (\n args: Array<string>,\n cwd?: string,\n options?: execa.Options\n ) => execa.ExecaChildProcess<string>\n ) {}\n private diffSummaries = new TypedEventEmitter<\"data\", GitHubDiffSummary[]>();\n\n onChangeDiffSummaries(\n callback: (result: Result<GitHubDiffSummary[]>) => unknown\n ): Disposable {\n const handleData = (data: GitHubDiffSummary[]) => callback({ value: data });\n const handleError = (error: Error) => callback({ error });\n this.diffSummaries.on(\"data\", handleData);\n this.diffSummaries.on(\"error\", handleError);\n return {\n dispose: () => {\n this.diffSummaries.off(\"data\", handleData);\n this.diffSummaries.off(\"error\", handleError);\n },\n };\n }\n\n public async triggerDiffSummariesFetch(_diffs: Array<PRNumber>) {\n const value = await this.runCommand([\"internal-only\", \"prs\"]);\n const prs = JSON.parse(value.stdout) as PRInfo[];\n this.diffSummaries.emit(\"data\", prs);\n }\n\n public dispose() {\n this.diffSummaries.removeAllListeners();\n }\n\n public getSummaryName(): string {\n return `github:${this.codeReviewSystem.hostname}/${this.codeReviewSystem.owner}/${this.codeReviewSystem.repo}`;\n }\n\n /** Run a command not handled within graphite, such as a separate submit handler */\n public runExternalCommand(\n _cwd: string,\n _args: Array<string>,\n _onProgress: OperationCommandProgressReporter,\n _signal: AbortSignal\n ): Promise<void> {\n throw new Error(\n \"GitHub code review provider does not support running external commands\"\n );\n }\n\n public async typeahead(\n _kind: TypeaheadKind,\n _query: string\n ): Promise<Array<TypeaheadResult>> {\n return Promise.resolve([]);\n }\n}\n\n// function githubCheckSuitesToCIStatus(\n// checkSuites: CheckSuiteConnection | undefined | null,\n// ): DiffSignalSummary {\n// let anyInProgress = false;\n// let anyWarning = false;\n// for (const checkSuite of checkSuites?.nodes ?? []) {\n// switch (checkSuite?.status) {\n// case CheckStatusState.Completed:\n// {\n// switch (checkSuite?.conclusion) {\n// case CheckConclusionState.Success:\n// break;\n// case CheckConclusionState.Neutral:\n// case CheckConclusionState.Stale:\n// case CheckConclusionState.Skipped:\n// anyWarning = true;\n// break;\n// case CheckConclusionState.ActionRequired:\n// case CheckConclusionState.StartupFailure:\n// case CheckConclusionState.Cancelled:\n// case CheckConclusionState.TimedOut:\n// case CheckConclusionState.Failure:\n// return 'failed'; // no need to look at other signals\n// }\n// }\n// break;\n// case CheckStatusState.Waiting:\n// case CheckStatusState.Requested:\n// case CheckStatusState.Queued:\n// case CheckStatusState.Pending:\n// case CheckStatusState.InProgress:\n// anyInProgress = true;\n// break;\n// }\n// }\n// return anyWarning ? 'warning' : anyInProgress ? 'running' : 'pass';\n// }\n","import type {\n Logger,\n OperationCommandProgressReporter,\n OperationProgress,\n RunnableOperation,\n} from \"@withgraphite/gti-shared\";\nimport { newAbortController } from \"@withgraphite/gti-shared\";\n\nimport type { ServerSideTracker } from \"./analytics/serverSideTracker\";\n\n/**\n * Handle running & queueing all Operations so that only one Operation runs at once.\n * Operations may be run by gt in the Repository or other providers like ghstack in the RemoteRepository.\n */\nexport class OperationQueue {\n constructor(\n private logger: Logger,\n private runCallback: (\n operation: RunnableOperation,\n cwd: string,\n handleProgress: OperationCommandProgressReporter,\n signal: AbortSignal\n ) => Promise<void>\n ) {}\n\n private queuedOperations: Array<\n RunnableOperation & { tracker: ServerSideTracker }\n > = [];\n private runningOperation: RunnableOperation | undefined = undefined;\n private abortController: AbortController | undefined = undefined;\n\n async runOrQueueOperation(\n operation: RunnableOperation,\n onProgress: (progress: OperationProgress) => void,\n tracker: ServerSideTracker,\n cwd: string\n ): Promise<void> {\n if (this.runningOperation != null) {\n this.queuedOperations.push({ ...operation, tracker });\n onProgress({\n id: operation.id,\n kind: \"queue\",\n queue: this.queuedOperations.map((o) => o.id),\n });\n return;\n }\n this.runningOperation = operation;\n\n const handleCommandProgress: OperationCommandProgressReporter = (\n ...args\n ) => {\n switch (args[0]) {\n case \"spawn\":\n onProgress({\n id: operation.id,\n kind: \"spawn\",\n queue: this.queuedOperations.map((op) => op.id),\n });\n break;\n\n case \"stdout\":\n onProgress({ id: operation.id, kind: \"stdout\", message: args[1] });\n break;\n\n case \"stderr\":\n onProgress({ id: operation.id, kind: \"stderr\", message: args[1] });\n break;\n\n case \"exit\":\n onProgress({\n id: operation.id,\n kind: \"exit\",\n exitCode: args[1],\n timestamp: Date.now(),\n });\n break;\n }\n };\n\n try {\n const controller = newAbortController();\n this.abortController = controller;\n await tracker.operation(\n operation.trackEventName,\n \"RunOperationError\",\n { extras: { args: operation.args, runner: operation.runner } },\n (_p) =>\n this.runCallback(\n operation,\n cwd,\n handleCommandProgress,\n controller.signal\n )\n );\n this.runningOperation = undefined;\n\n // now that we successfully ran this operation, dequeue the next\n if (this.queuedOperations.length > 0) {\n const op = this.queuedOperations.shift();\n if (op != null) {\n // don't await this, the caller should resolve when the original operation finishes.\n void this.runOrQueueOperation(\n op,\n // TODO: we're using the onProgress from the LAST `runOperation`... should we be keeping the newer onProgress in the queued operation?\n onProgress,\n op.tracker,\n cwd\n );\n }\n }\n } catch (err) {\n const errString = (err as Error).toString();\n this.logger.log(\n \"error running operation: \",\n operation.args[0],\n errString\n );\n onProgress({ id: operation.id, kind: \"error\", error: errString });\n // clear queue to run when we hit an error\n this.queuedOperations = [];\n this.runningOperation = undefined;\n }\n }\n\n /**\n * Send kill signal to the running operation if the operationId matches.\n * If the process exits, the exit event will be noticed by the queue.\n * This function does not block on waiting for the operation process to exit.\n */\n abortRunningOperation(operationId: string) {\n if (this.runningOperation?.id == operationId) {\n this.abortController?.abort();\n }\n }\n}\n","import type { PageVisibility } from \"@withgraphite/gti-shared\";\n\n/**\n * Aggregates if any GTI page has focus or visibility.\n */\nexport class PageFocusTracker {\n private focusedPages = new Set();\n private visiblePages = new Set();\n\n private onChangeHandlers = new Set<(state: PageVisibility) => unknown>();\n\n setState(page: string, state: PageVisibility) {\n switch (state) {\n case \"focused\":\n this.focusedPages.add(page);\n this.visiblePages.add(page);\n break;\n\n case \"visible\":\n this.focusedPages.delete(page);\n this.visiblePages.add(page);\n break;\n\n case \"hidden\":\n this.focusedPages.delete(page);\n this.visiblePages.delete(page);\n break;\n }\n for (const handler of this.onChangeHandlers) {\n handler(state);\n }\n }\n\n public disposePage(page: string) {\n this.focusedPages.delete(page);\n this.visiblePages.delete(page);\n }\n\n public hasPageWithFocus() {\n return this.focusedPages.size > 0;\n }\n public hasVisiblePage() {\n return this.visiblePages.size > 0;\n }\n\n public onChange(callback: () => unknown): () => void {\n this.onChangeHandlers.add(callback);\n return () => this.onChangeHandlers.delete(callback);\n }\n}\n","import { TypedEventEmitter } from \"./TypedEventEmitter\";\n\ntype Id = number;\n\n/**\n * Rate limits requests to run an arbitrary task.\n * Up to `maxSimultaneousRunning` tasks can run at once,\n * futher requests will be queued and run when a running task finishes.\n *\n * Usage:\n * ```\n * const rateLimiter = new RateLimiter(5);\n * const result = await rateLimiter.enqueueRun(() => {\n * // ...do arbitrary async work...\n * });\n * ```\n */\nexport class RateLimiter {\n private queued: Array<Id> = [];\n private running: Array<Id> = [];\n private runs = new TypedEventEmitter<\"run\", Id>();\n\n constructor(\n private maxSimultaneousRunning: number,\n private log?: (s: string) => unknown\n ) {}\n\n private nextId = 1;\n private generateId(): Id {\n return this.nextId++;\n }\n\n async enqueueRun<T>(runner: () => Promise<T>): Promise<T> {\n const id = this.generateId();\n\n this.queued.push(id);\n this.tryDequeueNext();\n\n if (!this.running.includes(id)) {\n this.log?.(\n `${this.running.length} tasks are already running, enqueuing ID:${id}`\n );\n await new Promise((res) => {\n this.runs.on(\"run\", (ran) => {\n if (ran === id) {\n this.log?.(`now allowing ID:${id} to run`);\n res(undefined);\n }\n });\n });\n }\n\n try {\n return await runner();\n } finally {\n this.notifyFinished(id);\n }\n }\n\n private notifyFinished(id: Id): void {\n this.running = this.running.filter((running) => running !== id);\n this.tryDequeueNext();\n }\n\n private tryDequeueNext() {\n if (this.running.length < this.maxSimultaneousRunning) {\n const toRun = this.queued.shift();\n if (toRun != null) {\n this.run(toRun);\n }\n }\n }\n\n private run(id: Id) {\n this.running.push(id);\n this.runs.emit(\"run\", id);\n }\n}\n","import type { BranchInfo } from \"@withgraphite/gti-cli-shared-types\";\nimport type { SmartlogCommits } from \"@withgraphite/gti-shared\";\nimport { truncate } from \"@withgraphite/gti-shared\";\nimport type { ExecaChildProcess } from \"execa\";\nimport type execa from \"execa\";\nimport os from \"os\";\n\nexport function sleep(timeMs: number): Promise<void> {\n return new Promise((res) => setTimeout(res, timeMs));\n}\n\nexport function firstOfIterable<T>(\n iterable: IterableIterator<T>\n): T | undefined {\n return iterable.next().value;\n}\n\n/**\n * Limits async function execution parallelism to only one at a time.\n * Hence, if a call is already running, it will wait for it to finish,\n * then start the next async execution, but if called again while not finished,\n * it will return the scheduled execution promise.\n *\n * Sample Usage:\n * ```\n * let i = 1;\n * const oneExecAtATime = serializeAsyncCall(() => {\n * return new Promise((resolve, reject) => {\n * setTimeout(200, () => resolve(i++));\n * });\n * });\n *\n * const result1Promise = oneExecAtATime(); // Start an async, and resolve to 1 in 200 ms.\n * const result2Promise = oneExecAtATime(); // Schedule the next async, and resolve to 2 in 400 ms.\n * const result3Promise = oneExecAtATime(); // Reuse scheduled promise and resolve to 2 in 400 ms.\n * ```\n */\nexport function serializeAsyncCall<T>(\n asyncFun: () => Promise<T>\n): () => Promise<T> {\n let scheduledCall: Promise<T> | undefined = undefined;\n let pendingCall: Promise<undefined> | undefined = undefined;\n const startAsyncCall = () => {\n const resultPromise = asyncFun();\n pendingCall = resultPromise.then(\n () => (pendingCall = undefined),\n () => (pendingCall = undefined)\n );\n return resultPromise;\n };\n const callNext = () => {\n scheduledCall = undefined;\n return startAsyncCall();\n };\n const scheduleNextCall = () => {\n if (scheduledCall == null) {\n if (pendingCall == null) {\n throw new Error(\"pendingCall must not be null!\");\n }\n scheduledCall = pendingCall.then(callNext, callNext);\n }\n return scheduledCall;\n };\n return () => {\n if (pendingCall == null) {\n return startAsyncCall();\n } else {\n return scheduleNextCall();\n }\n };\n}\n\n/**\n * Kill `child` on `AbortSignal`.\n *\n * This is slightly more robust than execa 6.0 and nodejs' `signal` support:\n * if a process was stopped (by `SIGTSTP` or `SIGSTOP`), it can still be killed.\n */\nexport function handleAbortSignalOnProcess(\n child: ExecaChildProcess,\n signal: AbortSignal\n) {\n signal.addEventListener(\"abort\", () => {\n if (os.platform() == \"win32\") {\n // Signals are ignored on Windows.\n // execa's default forceKillAfterTimeout behavior does not\n // make sense for Windows. Disable it explicitly.\n child.kill(\"SIGKILL\", { forceKillAfterTimeout: false });\n } else {\n // If the process is stopped (ex. Ctrl+Z, kill -STOP), make it\n // continue first so it can respond to signals including SIGKILL.\n child.kill(\"SIGCONT\");\n // A good citizen process should exit soon after recieving SIGTERM.\n // In case it doesn't, send SIGKILL after 5 seconds.\n child.kill(\"SIGTERM\", { forceKillAfterTimeout: 5000 });\n }\n });\n}\n\n/**\n * Given a list of commits and a starting commit,\n * traverse up the chain of `parents` until we find a public commit\n */\nexport function findPublicAncestor(\n allCommits: SmartlogCommits | undefined,\n from: BranchInfo\n): BranchInfo | undefined {\n let publicCommit: BranchInfo | undefined;\n if (allCommits != null) {\n const map = new Map(allCommits.map((commit) => [commit.branch, commit]));\n\n let current: BranchInfo | undefined = from;\n while (current != null) {\n if (current.partOfTrunk) {\n publicCommit = current;\n break;\n }\n if (current.parents[0] == null) {\n break;\n }\n current = map.get(current.parents[0]);\n }\n }\n\n return publicCommit;\n}\n\n/**\n * Run a command that is expected to produce JSON output.\n * Return a JSON object. On error, the JSON object has property \"error\".\n */\nexport function parseExecJson<T>(\n exec: execa.ExecaChildProcess,\n reply: (parsed?: T, error?: string) => void\n) {\n exec\n .then((result) => {\n const stdout = result.stdout;\n try {\n const parsed = JSON.parse(stdout);\n if (parsed.error != null) {\n reply(undefined, parsed.error);\n } else {\n reply(parsed as T);\n }\n } catch (err) {\n const msg = `Cannot parse ${truncate(\n result.escapedCommand\n )} output. (error: ${err}, stdout: ${stdout})`;\n reply(undefined, msg);\n }\n })\n .catch((err) => {\n // Try extracting error from stdout '{error: message}'.\n try {\n const parsed = JSON.parse(err.stdout);\n if (parsed.error != null) {\n reply(undefined, parsed.error);\n return;\n }\n } catch {\n // pass\n }\n // Fallback to general error.\n const msg = `Cannot run ${truncate(err.escapedCommand)}. (error: ${err})`;\n reply(undefined, msg);\n });\n}\n","import type { Logger } from \"@withgraphite/gti-shared\";\nimport { EventEmitter } from \"events\";\nimport watchman from \"fb-watchman\";\nimport path from \"path\";\n\nimport { firstOfIterable, serializeAsyncCall, sleep } from \"./utils\";\n\nexport type WatchmanSubscriptionOptions = {\n fields?: Array<string>;\n expression?: Array<unknown>;\n since?: string;\n defer?: Array<string>;\n defer_vcs?: boolean;\n relative_root?: string;\n empty_on_fresh_instance?: boolean;\n};\n\nexport type WatchmanSubscription = {\n root: string;\n /**\n * The relative path from subscriptionRoot to subscriptionPath.\n * This is the 'relative_path' as described at\n * https://facebook.github.io/watchman/docs/cmd/watch-project.html#using-watch-project.\n * Notably, this value should be undefined if subscriptionRoot is the same as\n * subscriptionPath.\n */\n pathFromSubscriptionRootToSubscriptionPath: string | undefined;\n path: string;\n name: string;\n subscriptionCount: number;\n options: WatchmanSubscriptionOptions;\n emitter: EventEmitter;\n};\n\nexport type WatchmanSubscriptionResponse = {\n root: string;\n subscription: string;\n files?: Array<FileChange>;\n \"state-enter\"?: string;\n \"state-leave\"?: string;\n canceled?: boolean;\n clock?: string;\n is_fresh_instance?: boolean;\n};\n\nexport type FileChange = {\n name: string;\n new: boolean;\n exists: boolean;\n};\n\nconst WATCHMAN_SETTLE_TIME_MS = 2500;\nconst DEFAULT_WATCHMAN_RECONNECT_DELAY_MS = 100;\nconst MAXIMUM_WATCHMAN_RECONNECT_DELAY_MS = 60 * 1000;\n\nexport class Watchman {\n private client: watchman.Client;\n\n private serializedReconnect: () => Promise<void>;\n private reconnectDelayMs: number = DEFAULT_WATCHMAN_RECONNECT_DELAY_MS;\n private subscriptions: Map<string, WatchmanSubscription> = new Map();\n private lastKnownClockTimes: Map<string, string> = new Map();\n\n public readonly status:\n | \"initializing\"\n | \"reconnecting\"\n | \"healthy\"\n | \"ended\"\n | \"errored\" = \"initializing\";\n\n constructor(private logger: Logger) {\n this.client = new watchman.Client({\n // find watchman using PATH\n watchmanBinaryPath: undefined,\n });\n this.initWatchmanClient();\n this.serializedReconnect = serializeAsyncCall(async () => {\n let tries = 0;\n // eslint-disable-next-line no-constant-condition\n while (true) {\n try {\n // eslint-disable-next-line no-await-in-loop\n await this.reconnectClient();\n return;\n } catch (error) {\n this.logger.warn(\n `reconnectClient failed (try #${tries}):`,\n error instanceof Error ? error.message : error\n );\n tries++;\n\n this.reconnectDelayMs *= 2; // exponential backoff\n if (this.reconnectDelayMs > MAXIMUM_WATCHMAN_RECONNECT_DELAY_MS) {\n this.reconnectDelayMs = MAXIMUM_WATCHMAN_RECONNECT_DELAY_MS;\n }\n\n this.logger.info(\n \"Calling reconnectClient from _serializedReconnect in %dms\",\n this.reconnectDelayMs\n );\n // eslint-disable-next-line no-await-in-loop\n await sleep(this.reconnectDelayMs);\n }\n }\n });\n }\n\n setStatus(status: typeof this.status): void {\n this.logger.log(\"Watchman status: \", status);\n (this.status as string) = status;\n }\n\n public async watchDirectoryRecursive(\n localDirectoryPath: string,\n rawSubscriptionName: string,\n subscriptionOptions?: WatchmanSubscriptionOptions\n ): Promise<WatchmanSubscription> {\n // Subscriptions should be unique by name and by folder\n const subscriptionName = this.fixupName(\n localDirectoryPath,\n rawSubscriptionName\n );\n const existingSubscription = this.getSubscription(subscriptionName);\n if (existingSubscription) {\n existingSubscription.subscriptionCount++;\n\n return existingSubscription;\n } else {\n const { watch: watchRoot, relative_path: relativePath } =\n await this.watchProject(localDirectoryPath);\n const clock = await this.clock(watchRoot);\n const options: WatchmanSubscriptionOptions = {\n ...subscriptionOptions,\n // Do not add `mode` here, it is very unfriendly to watches on Eden (see https://fburl.com/0z023yy0)\n fields:\n subscriptionOptions != null && subscriptionOptions.fields != null\n ? subscriptionOptions.fields\n : [\"name\", \"new\", \"exists\"],\n since: clock,\n };\n if (relativePath) {\n options.relative_root = relativePath;\n }\n // Try this thing out where we always set empty_on_fresh_instance. Eden will be a lot happier\n // if we never ask Watchman to do something that results in a glob(**) near the root.\n options.empty_on_fresh_instance = true;\n\n // relativePath is undefined if watchRoot is the same as directoryPath.\n const subscription: WatchmanSubscription = {\n root: watchRoot,\n pathFromSubscriptionRootToSubscriptionPath: relativePath,\n path: localDirectoryPath,\n name: subscriptionName,\n subscriptionCount: 1,\n options,\n emitter: new EventEmitter(),\n };\n this.setSubscription(subscriptionName, subscription);\n await this.subscribe(watchRoot, subscriptionName, options);\n this.logger.log(\"watchman subscription %s established\", subscriptionName);\n this.setStatus(\"healthy\");\n\n return subscription;\n }\n }\n\n public async unwatch(path: string, name: string): Promise<void> {\n const subscriptionName = this.fixupName(path, name);\n const subscription = this.getSubscription(subscriptionName);\n\n if (subscription == null) {\n this.logger.error(\n `No watcher entity found with path [${path}] name [${name}]`\n );\n return;\n }\n\n if (--subscription.subscriptionCount === 0) {\n await this.unsubscribe(subscription.path, subscription.name);\n this.deleteSubscription(subscriptionName);\n this.logger.log(\"watchman subscription %s destroyed\", subscriptionName);\n }\n }\n\n private initWatchmanClient(): void {\n this.client.on(\"end\", () => {\n this.setStatus(\"ended\");\n this.logger.info(\"Watchman client ended\");\n this.client.removeAllListeners();\n void this.serializedReconnect();\n });\n this.client.on(\"error\", (error: Error) => {\n const statusBeforeError = this.status;\n this.logger.error(\"Error while talking to watchman: \", error);\n this.setStatus(\"errored\");\n // If Watchman encounters an error in the middle of a command, it may never finish!\n // The client must be immediately killed here so that the command fails and\n // `serializeAsyncCall` can be unblocked. Otherwise, we end up in a deadlock.\n this.client.removeAllListeners();\n this.client.end();\n if (statusBeforeError === \"initializing\") {\n // If we get an error while we're first initializing watchman, it probably means\n // it's not installed properly. No use spamming reconnection failures too.\n return;\n }\n // Those are errors in deserializing a stream of changes.\n // The only possible recovery here is reconnecting a new client,\n // but the failed to serialize events will be missed.\n void this.serializedReconnect();\n });\n this.client.on(\"subscription\", this.onSubscriptionResult.bind(this));\n }\n\n private async reconnectClient(): Promise<void> {\n // If we got an error after making a subscription, the reconnect needs to\n // remove that subscription to try again, so it doesn't keep leaking subscriptions.\n this.logger.info(\"Ending existing watchman client to reconnect a new one\");\n this.setStatus(\"reconnecting\");\n this.client.removeAllListeners();\n this.client.end();\n this.client = new watchman.Client({\n // find watchman using PATH\n watchmanBinaryPath: undefined,\n });\n this.logger.error(\n \"Watchman client disconnected, reconnecting a new client!\"\n );\n this.initWatchmanClient();\n this.logger.info(\"Watchman client re-initialized, restoring subscriptions\");\n await this.restoreSubscriptions();\n }\n\n private async restoreSubscriptions(): Promise<void> {\n const watchSubscriptions = Array.from(this.subscriptions.values());\n const numSubscriptions = watchSubscriptions.length;\n this.logger.info(\n `Attempting to restore ${numSubscriptions} Watchman subscriptions.`\n );\n let numRestored = 0;\n await Promise.all(\n watchSubscriptions.map(\n async (subscription: WatchmanSubscription, index: number) => {\n // Note that this call to `watchman watch-project` could fail if the\n // subscription.path has been unmounted/deleted.\n await this.watchProject(subscription.path);\n\n // We have already missed the change events from the disconnect time,\n // watchman could have died, so the last clock result is not valid.\n await sleep(WATCHMAN_SETTLE_TIME_MS);\n\n // Register the subscriptions after the filesystem settles.\n const { name, options, root } = subscription;\n\n // Assuming we had previously connected and gotten an event, we can\n // reconnect `since` that time, so that we get any events we missed.\n subscription.options.since =\n this.lastKnownClockTimes.get(root) || (await this.clock(root));\n\n this.logger.info(\n `Subscribing to ${name}: (${index + 1}/${numSubscriptions})`\n );\n await this.subscribe(root, name, options);\n ++numRestored;\n this.logger.info(\n `Subscribed to ${name}: (${numRestored}/${numSubscriptions}) complete.`\n );\n }\n )\n );\n if (numRestored > 0 && numRestored === numSubscriptions) {\n this.logger.info(\n \"Successfully reconnected all %d subscriptions.\",\n numRestored\n );\n // if everything got restored, reset the reconnect backoff time\n this.reconnectDelayMs = DEFAULT_WATCHMAN_RECONNECT_DELAY_MS;\n this.setStatus(\"healthy\");\n }\n }\n\n private getSubscription(entryPath: string): WatchmanSubscription | undefined {\n return this.subscriptions.get(path.normalize(entryPath));\n }\n\n private setSubscription(\n entryPath: string,\n subscription: WatchmanSubscription\n ): void {\n const key = path.normalize(entryPath);\n this.subscriptions.set(key, subscription);\n }\n\n private deleteSubscription(entryPath: string): void {\n const key = path.normalize(entryPath);\n this.subscriptions.delete(key);\n }\n\n private onSubscriptionResult(response: WatchmanSubscriptionResponse): void {\n const subscription = this.getSubscription(response.subscription);\n if (subscription == null) {\n this.logger.error(\"Subscription not found for response:!\", response);\n return;\n }\n\n // save the clock time of this event in case we disconnect in the future\n if (response != null && response.root != null && response.clock != null) {\n this.lastKnownClockTimes.set(response.root, response.clock);\n }\n if (response.is_fresh_instance === true) {\n this.logger.warn(\n `Watch for ${response.root} (${response.subscription}) returned an empty fresh instance.`\n );\n subscription.emitter.emit(\"fresh-instance\");\n } else if (Array.isArray(response.files)) {\n subscription.emitter.emit(\"change\", response.files);\n } else if (response.canceled === true) {\n this.logger.info(\n `Watch for ${response.root} was deleted: triggering a reconnect.`\n );\n // Ending the client will trigger a reconnect.\n this.client.end();\n } else {\n // Only log state transisions once per watchmanClient, since otherwise we'll just get 8x of this message spammed\n if (firstOfIterable(this.subscriptions.values()) === subscription) {\n // TODO(most): use state messages to decide on when to send updates.\n const stateEnter = response[\"state-enter\"];\n const stateLeave = response[\"state-leave\"];\n const stateMessage =\n stateEnter != null\n ? `Entering ${stateEnter}`\n : `Leaving ${stateLeave}`;\n const numSubscriptions = this.subscriptions.size;\n this.logger.info(\n `Subscription state: ${stateMessage} (${numSubscriptions})`\n );\n }\n }\n }\n\n private fixupName(path: string, name: string): string {\n const refinedPath = path.replace(/\\\\/g, \"-\").replace(/\\//g, \"-\");\n return `${refinedPath}-${name}`;\n }\n\n private unsubscribe(\n subscriptionPath: string,\n subscriptionName: string\n ): Promise<unknown> {\n return this.command(\"unsubscribe\", subscriptionPath, subscriptionName);\n }\n\n private async watchProject(\n directoryPath: string\n ): Promise<{ watch: string; relative_path: string }> {\n const response = (await this.command(\"watch-project\", directoryPath)) as {\n watch: string;\n relative_path: string;\n warning?: string;\n };\n if (response.warning) {\n this.logger.error(\"watchman warning: \", response.warning);\n }\n return response;\n }\n\n private async clock(directoryPath: string): Promise<string> {\n const { clock } = (await this.command(\"clock\", directoryPath)) as {\n clock: string;\n };\n return clock;\n }\n\n private subscribe(\n watchRoot: string,\n subscriptionName: string | undefined,\n options: WatchmanSubscriptionOptions\n ): Promise<WatchmanSubscription> {\n this.logger.info(\n `Creating Watchman subscription ${String(\n subscriptionName\n )} under ${watchRoot}`,\n JSON.stringify(options)\n );\n return this.command(\n \"subscribe\",\n watchRoot,\n subscriptionName,\n options\n ) as Promise<WatchmanSubscription>;\n }\n\n /**\n * Promisify calls to watchman client.\n */\n private async command(...args: Array<unknown>): Promise<unknown> {\n try {\n return await new Promise((resolve, reject) => {\n this.client.command(args, (error, response) =>\n error ? reject(error) : resolve(response)\n );\n });\n } catch (error) {\n this.logger.error(\"Watchman command error: \", args, error);\n throw error;\n }\n }\n}\n","import type {\n Logger,\n PageVisibility,\n RepoInfo,\n} from \"@withgraphite/gti-shared\";\nimport { debounce, ONE_MINUTE_MS } from \"@withgraphite/gti-shared\";\nimport path from \"path\";\n\nimport type { PageFocusTracker } from \"./PageFocusTracker\";\nimport { Watchman } from \"./watchman\";\n\nconst DEFAULT_POLL_INTERVAL = 5 * ONE_MINUTE_MS;\nconst VISIBLE_POLL_INTERVAL = 1 * ONE_MINUTE_MS;\nconst FOCUSED_POLL_INTERVAL = 0.25 * ONE_MINUTE_MS;\nconst ON_FOCUS_REFETCH_THROTTLE = 10_000;\nconst ON_VISIBLE_REFETCH_THROTTLE = 20_000;\n\nexport type KindOfChange =\n | \"uncommitted changes\"\n | \"branches\"\n | \"merge conflicts\"\n | \"everything\";\n\n/**\n * Handles watching for changes to files on disk which should trigger refetching data,\n * and polling for changes when watching is not reliable.\n */\nexport class WatchForChanges {\n static WATCHMAN_DEFER = `hg.update`; // TODO: update to sl\n public watchman: Watchman;\n\n private disposables: Array<() => unknown> = [];\n\n // eslint-disable-next-line max-params\n constructor(\n private repoInfo: RepoInfo,\n private logger: Logger,\n private pageFocusTracker: PageFocusTracker,\n private changeCallback: (kind: KindOfChange) => unknown,\n watchman?: Watchman | undefined\n ) {\n this.watchman = watchman ?? new Watchman(logger);\n\n void this.setupWatchmanSubscriptions();\n this.setupPolling();\n this.pageFocusTracker.onChange(this.poll.bind(this));\n }\n\n private timeout: NodeJS.Timeout | undefined;\n private lastFetch = new Date().valueOf();\n\n /**\n * Combine different signals to determine what interval to poll for information\n */\n private setupPolling() {\n this.timeout = setTimeout(this.poll, DEFAULT_POLL_INTERVAL);\n }\n\n /**\n * Re-trigger fetching data from the repository,\n * depending on how recently that data was last fetched,\n * and whether any GTI windows are focused or visible.\n *\n * This function calls itself on an interval to check whether we should fetch changes,\n * but it can also be called in response to events like focus being gained.\n */\n public poll = (kind?: PageVisibility | \"force\") => {\n // calculate how long we'd like to be waiting from what we know of the windows.\n let desiredNextTickTime = DEFAULT_POLL_INTERVAL;\n if (this.watchman.status !== \"healthy\") {\n if (this.pageFocusTracker.hasPageWithFocus()) {\n desiredNextTickTime = FOCUSED_POLL_INTERVAL;\n } else if (this.pageFocusTracker.hasVisiblePage()) {\n desiredNextTickTime = VISIBLE_POLL_INTERVAL;\n }\n }\n\n const now = Date.now();\n const elapsedTickTime = now - this.lastFetch;\n\n if (\n kind === \"force\" ||\n // we've been waiting longer than desired\n elapsedTickTime >= desiredNextTickTime ||\n // the moment a window gains focus or visibility, consider polling immediately\n (kind === \"focused\" && elapsedTickTime >= ON_FOCUS_REFETCH_THROTTLE) ||\n (kind === \"visible\" && elapsedTickTime >= ON_VISIBLE_REFETCH_THROTTLE)\n ) {\n // it's time to fetch\n this.changeCallback(\"everything\");\n this.lastFetch = Date.now();\n\n clearTimeout(this.timeout);\n this.timeout = setTimeout(this.poll, desiredNextTickTime);\n } else {\n // we have some time left before we we would expect to need to poll, schedule next poll\n clearTimeout(this.timeout);\n this.timeout = setTimeout(\n this.poll,\n desiredNextTickTime - elapsedTickTime\n );\n }\n };\n\n private async setupWatchmanSubscriptions() {\n if (this.repoInfo.type !== \"success\") {\n return;\n }\n const { repoRoot, dotdir } = this.repoInfo;\n\n if (repoRoot == null || dotdir == null) {\n this.logger.error(\n `skipping watchman subscription since ${repoRoot} is not a repository`\n );\n return;\n }\n const relativeDotdir = path.relative(repoRoot, dotdir);\n\n const FILE_CHANGE_WATCHMAN_SUBSCRIPTION = \"graphite-smartlog-file-change\";\n const DIRSTATE_WATCHMAN_SUBSCRIPTION = \"graphite-smartlog-dirstate-change\";\n try {\n const handleRepositoryStateChange = debounce(() => {\n // if the repo changes, also recheck files. E.g. if you commit, your uncommitted changes will also change.\n this.changeCallback(\"everything\");\n\n // reset timer for polling\n this.lastFetch = new Date().valueOf();\n }, 100); // debounce so that multiple quick changes don't trigger multiple fetches for no reason\n const dirstateSubscription = await this.watchman.watchDirectoryRecursive(\n repoRoot,\n DIRSTATE_WATCHMAN_SUBSCRIPTION,\n {\n fields: [\"name\"],\n expression: [\n \"name\",\n [\n `${relativeDotdir}/refs/heads`,\n `${relativeDotdir}/refs/branch-metadata`,\n `${relativeDotdir}/rebase-merge`,\n `${relativeDotdir}/index`,\n `${relativeDotdir}/HEAD`,\n ],\n \"wholename\",\n ],\n defer: [WatchForChanges.WATCHMAN_DEFER],\n empty_on_fresh_instance: true,\n }\n );\n dirstateSubscription.emitter.on(\"change\", (changes) => {\n if (changes.includes(`${relativeDotdir}/rebase-merge`)) {\n this.changeCallback(\"merge conflicts\");\n }\n if (changes.includes(`${relativeDotdir}/index`)) {\n this.changeCallback(\"uncommitted changes\");\n }\n if (\n changes.includes(`${relativeDotdir}/refs/heads`) ||\n changes.includes(`${relativeDotdir}/refs/branch-metadata`) ||\n changes.includes(`${relativeDotdir}/HEAD`)\n ) {\n this.changeCallback(\"branches\");\n }\n });\n dirstateSubscription.emitter.on(\n \"fresh-instance\",\n handleRepositoryStateChange\n );\n\n const handleUncommittedChanges = () => {\n this.changeCallback(\"uncommitted changes\");\n\n // reset timer for polling\n this.lastFetch = new Date().valueOf();\n };\n const uncommittedChangesSubscription =\n await this.watchman.watchDirectoryRecursive(\n repoRoot,\n FILE_CHANGE_WATCHMAN_SUBSCRIPTION,\n {\n // We only need to know that a change happened (not the list of files) so that we can trigger `status`\n fields: [\"name\"],\n expression: [\n \"allof\",\n // This watchman subscription is used to determine when and which\n // files to fetch new statuses for. There is no reason to include\n // directories in these updates, and in fact they may make us overfetch\n // statuses.\n // This line restricts this subscription to only return files.\n [\"type\", \"f\"],\n [\"not\", [\"dirname\", relativeDotdir]],\n // Even though we tell it not to match .git, modifying a file inside .git\n // will emit an event for the folder itself, which we want to ignore.\n [\"not\", [\"match\", relativeDotdir, \"basename\"]],\n ],\n defer: [WatchForChanges.WATCHMAN_DEFER],\n empty_on_fresh_instance: true,\n }\n );\n uncommittedChangesSubscription.emitter.on(\n \"change\",\n handleUncommittedChanges\n );\n uncommittedChangesSubscription.emitter.on(\n \"fresh-instance\",\n handleUncommittedChanges\n );\n\n this.disposables.push(() => {\n void this.watchman.unwatch(repoRoot, DIRSTATE_WATCHMAN_SUBSCRIPTION);\n void this.watchman.unwatch(repoRoot, FILE_CHANGE_WATCHMAN_SUBSCRIPTION);\n });\n } catch (err) {\n this.logger.error(\"failed to setup watchman subscriptions\", err);\n }\n }\n\n public dispose() {\n this.disposables.forEach((dispose) => dispose());\n if (this.timeout) {\n clearTimeout(this.timeout);\n this.timeout = undefined;\n }\n }\n}\n","import type {\n BranchInfo,\n PRNumber,\n RepoInfo as RepoInfoFromCLI,\n RepoRelativePath,\n Status,\n} from \"@withgraphite/gti-cli-shared-types\";\nimport type {\n AbsolutePath,\n CodeReviewSystem,\n CommandArg,\n Disposable,\n FetchedCommits,\n FetchedUncommittedChanges,\n Logger,\n MergeConflicts,\n OperationCommandProgressReporter,\n OperationProgress,\n PageVisibility,\n RepoInfo,\n RunnableOperation,\n SmartlogCommits,\n SuccessorInfo,\n ValidatedRepoInfo,\n} from \"@withgraphite/gti-shared\";\nimport {\n CommandRunner,\n Comparison,\n ComparisonType,\n DEFAULT_DAYS_OF_COMMITS_TO_LOAD,\n ErrorShortMessages,\n notEmpty,\n unwrap,\n} from \"@withgraphite/gti-shared\";\nimport execa from \"execa\";\nimport path from \"path\";\nimport semver from \"semver\";\n\nimport type { ServerSideTracker } from \"./analytics/serverSideTracker\";\nimport { exists, removeLeadingPathSep } from \"./fs\";\nimport { GitHubCodeReviewProvider } from \"./github/githubCodeReviewProvider\";\nimport { OperationQueue } from \"./OperationQueue\";\nimport { PageFocusTracker } from \"./PageFocusTracker\";\nimport { RateLimiter } from \"./RateLimiter\";\nimport { TypedEventEmitter } from \"./TypedEventEmitter\";\nimport { handleAbortSignalOnProcess, serializeAsyncCall } from \"./utils\";\nimport { WatchForChanges } from \"./WatchForChanges\";\n\nexport const COMMIT_END_MARK = \"<<COMMIT_END_MARK>>\";\nexport const NULL_CHAR = \"\\0\";\nconst MAX_SIMULTANEOUS_CAT_CALLS = 4;\n\nconst MIN_REQUIRED_CLI_VERSION = \"0.1.4\";\n\ntype ConflictFileData = {\n contents: string;\n exists: boolean;\n isexec: boolean;\n issymlink: boolean;\n};\nexport type ResolveCommandConflictOutput = [\n | {\n command: null;\n conflicts: [];\n pathconflicts: [];\n }\n | {\n command: string;\n command_details: { cmd: string; to_abort: string; to_continue: string };\n conflicts: Array<{\n base: ConflictFileData;\n local: ConflictFileData;\n output: ConflictFileData;\n other: ConflictFileData;\n path: string;\n }>;\n pathconflicts: Array<never>;\n }\n];\n\n/**\n * This class is responsible for providing information about the working copy\n * for a Graphite repository.\n *\n * A Repository may be reused by multiple connections, not just one GTI window.\n * This is so we don't duplicate watchman subscriptions and calls to status/log.\n * A Repository does not have a pre-defined `cwd`, so it may be re-used across cwds.\n *\n * Prefer using `RepositoryCache.getOrCreate()` to access and dispose `Repository`s.\n */\nexport class Repository {\n public IGNORE_COMMIT_MESSAGE_LINES_REGEX = /^((?:HG|SL):.*)/gm;\n\n private mergeConflicts: MergeConflicts | undefined = undefined;\n private uncommittedChanges: FetchedUncommittedChanges | null = null;\n private smartlogCommits: FetchedCommits | null = null;\n\n private mergeConflictsEmitter = new TypedEventEmitter<\n \"change\",\n MergeConflicts | undefined\n >();\n private uncommittedChangesEmitter = new TypedEventEmitter<\n \"change\",\n FetchedUncommittedChanges\n >();\n private smartlogCommitsChangesEmitter = new TypedEventEmitter<\n \"change\",\n FetchedCommits\n >();\n\n private smartlogCommitsBeginFetchingEmitter = new TypedEventEmitter<\n \"start\",\n undefined\n >();\n private uncommittedChangesBeginFetchingEmitter = new TypedEventEmitter<\n \"start\",\n undefined\n >();\n\n private disposables: Array<() => void> = [\n () => this.mergeConflictsEmitter.removeAllListeners(),\n () => this.uncommittedChangesEmitter.removeAllListeners(),\n () => this.smartlogCommitsChangesEmitter.removeAllListeners(),\n () => this.smartlogCommitsBeginFetchingEmitter.removeAllListeners(),\n () => this.uncommittedChangesBeginFetchingEmitter.removeAllListeners(),\n ];\n public onDidDispose(callback: () => unknown): void {\n this.disposables.push(callback);\n }\n\n private operationQueue: OperationQueue;\n private watchForChanges: WatchForChanges;\n private pageFocusTracker = new PageFocusTracker();\n public codeReviewProvider?: GitHubCodeReviewProvider;\n\n private currentVisibleCommitRangeIndex = 0;\n private visibleCommitRanges: Array<number | undefined> = [\n DEFAULT_DAYS_OF_COMMITS_TO_LOAD,\n 60,\n undefined,\n ];\n\n /** Prefer using `RepositoryCache.getOrCreate()` to access and dispose `Repository`s. */\n constructor(public info: ValidatedRepoInfo, public logger: Logger) {\n const remote = info.codeReviewSystem;\n if (remote.type === \"github\") {\n this.codeReviewProvider = new GitHubCodeReviewProvider(\n remote,\n this.runCommand.bind(this)\n );\n }\n\n this.watchForChanges = new WatchForChanges(\n info,\n logger,\n this.pageFocusTracker,\n (kind) => {\n if (kind === \"uncommitted changes\") {\n void this.fetchUncommittedChanges();\n } else if (kind === \"branches\") {\n void this.fetchSmartlogCommits();\n } else if (kind === \"merge conflicts\") {\n void this.checkForMergeConflicts();\n } else if (kind === \"everything\") {\n void this.fetchUncommittedChanges();\n void this.fetchSmartlogCommits();\n void this.checkForMergeConflicts();\n }\n }\n );\n\n this.operationQueue = new OperationQueue(\n this.logger,\n (\n operation: RunnableOperation,\n cwd: string,\n handleCommandProgress,\n signal: AbortSignal\n ): Promise<void> => {\n if (operation.runner === CommandRunner.Graphite) {\n return this.runOperation(\n operation,\n handleCommandProgress,\n cwd,\n signal\n );\n } else if (operation.runner === CommandRunner.CodeReviewProvider) {\n const normalizedArgs = this.normalizeOperationArgs(\n cwd,\n operation.args\n );\n\n if (this.codeReviewProvider?.runExternalCommand == null) {\n return Promise.reject(\n Error(\n \"CodeReviewProvider does not support running external commands\"\n )\n );\n }\n\n return (\n this.codeReviewProvider?.runExternalCommand(\n cwd,\n normalizedArgs,\n handleCommandProgress,\n signal\n ) ?? Promise.resolve()\n );\n }\n return Promise.resolve();\n }\n );\n\n // refetch summaries whenever we see new diffIds\n const seenDiffs = new Set();\n const subscription = this.subscribeToSmartlogCommitsChanges((fetched) => {\n if (fetched.commits.value) {\n const newDiffs = [];\n const diffIds = fetched.commits.value\n .filter((commit) => commit.pr)\n .map((commit) => commit.pr?.number);\n for (const diffId of diffIds) {\n if (!seenDiffs.has(diffId)) {\n newDiffs.push(diffId);\n seenDiffs.add(diffId);\n }\n }\n if (newDiffs.length > 0) {\n void this.codeReviewProvider?.triggerDiffSummariesFetch(\n // We could choose to only fetch the diffs that changed (`newDiffs`) rather than all diffs,\n // but our UI doesn't cache old values, thus all other diffs would appear empty\n this.getAllDiffIds()\n );\n }\n }\n });\n\n // the repo may already be in a conflict state on startup\n void this.checkForMergeConflicts();\n\n this.disposables.push(() => subscription.dispose());\n }\n\n public nextVisibleCommitRangeInDays(): number | undefined {\n if (\n this.currentVisibleCommitRangeIndex + 1 <\n this.visibleCommitRanges.length\n ) {\n this.currentVisibleCommitRangeIndex++;\n }\n return this.visibleCommitRanges[this.currentVisibleCommitRangeIndex];\n }\n\n /**\n * Typically, disposing is handled by `RepositoryCache` and not used directly.\n */\n public dispose() {\n this.disposables.forEach((dispose) => dispose());\n this.codeReviewProvider?.dispose();\n this.watchForChanges.dispose();\n }\n\n public onChangeConflictState(\n callback: (conflicts: MergeConflicts | undefined) => unknown\n ): Disposable {\n this.mergeConflictsEmitter.on(\"change\", callback);\n\n if (this.mergeConflicts) {\n // if we're already in merge conflicts, let the client know right away\n callback(this.mergeConflicts);\n }\n\n return {\n dispose: () => this.mergeConflictsEmitter.off(\"change\", callback),\n };\n }\n\n public checkForMergeConflicts = serializeAsyncCall(async () => {\n this.logger.info(\"checking for merge conflicts\");\n // Fast path: check if .git/merge dir changed\n const wasAlreadyInConflicts = this.mergeConflicts != null;\n if (!wasAlreadyInConflicts) {\n const mergeDirExists = await exists(\n path.join(this.info.dotdir, \"rebase-merge\")\n );\n if (!mergeDirExists) {\n // Not in a conflict\n this.logger.info(\n `conflict state still the same (${\n wasAlreadyInConflicts ? \"IN merge conflict\" : \"NOT in conflict\"\n })`\n );\n return;\n }\n }\n\n if (this.mergeConflicts == null) {\n // notify UI that merge conflicts were detected and full details are loading\n this.mergeConflicts = { state: \"loading\" };\n this.mergeConflictsEmitter.emit(\"change\", this.mergeConflicts);\n }\n\n // More expensive full check for conflicts. Necessary if we see .gt/merge change, or if\n // we're already in a conflict and need to re-check if a conflict was resolved.\n\n const fetchStartTimestamp = Date.now();\n let output: Status;\n try {\n const proc = await this.runCommand([\"internal-only\", \"status\"]);\n output = JSON.parse(proc.stdout) as Status;\n } catch (err) {\n this.logger.error(`failed to check for merge conflicts: ${err}`);\n // To avoid being stuck in \"loading\" state forever, let's pretend there's no conflicts.\n this.mergeConflicts = undefined;\n this.mergeConflictsEmitter.emit(\"change\", this.mergeConflicts);\n return;\n }\n\n this.mergeConflicts = computeNewConflicts(\n this.mergeConflicts,\n output,\n fetchStartTimestamp\n );\n this.logger.info(\n `repo ${this.mergeConflicts ? \"IS\" : \"IS NOT\"} in merge conflicts`\n );\n if (this.mergeConflicts) {\n const maxConflictsToLog = 20;\n const remainingConflicts = (this.mergeConflicts.files ?? [])\n .filter((conflict) => conflict.status === \"UNRESOLVED\")\n .map((conflict) => conflict.path)\n .slice(0, maxConflictsToLog);\n this.logger.info(\"remaining files with conflicts: \", remainingConflicts);\n }\n this.mergeConflictsEmitter.emit(\"change\", this.mergeConflicts);\n });\n\n public getMergeConflicts(): MergeConflicts | undefined {\n return this.mergeConflicts;\n }\n\n /**\n * Determine basic repo info including the root and important config values.\n * Resulting RepoInfo may have null fields if cwd is not a valid repo root.\n * Throws if `command` is not found.\n */\n static async getRepoInfo(\n command: string | undefined,\n logger: Logger,\n cwd: string\n ): Promise<RepoInfo> {\n const repoVersion = await findVersion(command, logger, cwd).catch(\n (err: Error) => err\n );\n if (repoVersion instanceof Error) {\n return { type: \"invalidCommand\", command: command ?? \"gt\" };\n }\n if (\n repoVersion !== \"local\" &&\n semver.lt(repoVersion, MIN_REQUIRED_CLI_VERSION)\n ) {\n return {\n type: \"invalidVersion\",\n command: command ?? \"gt\",\n versionFound: repoVersion,\n versionRequired: MIN_REQUIRED_CLI_VERSION,\n };\n }\n\n const [profile, repoInfoRaw, preferredBranchEdit, createPrsAs] =\n await Promise.all([\n findRepoProfile(command, logger, cwd),\n findRepoInfo(command, logger, cwd),\n getConfig(command, logger, cwd, \"graphite.branch_edit\").then(\n (value) => (value as \"commit\" | \"amend\") ?? (\"amend\" as const)\n ),\n getConfig(command, logger, cwd, \"graphite.create_prs_as\").then(\n (value) => (value as \"draft\" | \"publish\") ?? (\"draft\" as const)\n ),\n ]);\n if (repoInfoRaw == null) {\n return { type: \"cwdNotARepository\", cwd };\n }\n\n let codeReviewSystem: CodeReviewSystem;\n if (typeof repoInfoRaw.remote === \"undefined\") {\n codeReviewSystem = { type: \"none\" };\n } else {\n const { owner, name, hostname } = repoInfoRaw.remote;\n codeReviewSystem = {\n type: \"github\",\n owner,\n repo: name,\n hostname,\n };\n }\n\n const result: RepoInfo = {\n type: \"success\",\n command,\n dotdir: repoInfoRaw.dotDir,\n repoRoot: repoInfoRaw.rootDir,\n codeReviewSystem,\n preferredBranchEdit,\n createPrsAs,\n profile,\n trunkBranch: repoInfoRaw.trunkBranch,\n };\n logger.info(\"repo info: \", result);\n return result;\n }\n\n /**\n * Run long-lived command which mutates the repository state.\n * Progress is streamed back as it comes in.\n * Operations are run immediately. For queueing, see OperationQueue.\n */\n async runOrQueueOperation(\n operation: RunnableOperation,\n onProgress: (progress: OperationProgress) => void,\n tracker: ServerSideTracker,\n cwd: string\n ): Promise<void> {\n await this.operationQueue.runOrQueueOperation(\n operation,\n onProgress,\n tracker,\n cwd\n );\n\n // After any operation finishes, make sure we poll right away,\n // so the UI is guarnateed to get the latest data.\n this.watchForChanges.poll(\"force\");\n }\n\n /**\n * Abort the running operation if it matches the given id.\n */\n abortRunningOpeation(operationId: string) {\n this.operationQueue.abortRunningOperation(operationId);\n }\n\n /**\n * Called by this.operationQueue in response to runOrQueueOperation when an operation is ready to actually run.\n */\n private normalizeOperationArgs(\n cwd: string,\n args: Array<CommandArg>\n ): Array<string> {\n const repoRoot = unwrap(this.info.repoRoot);\n\n return args.map((arg) => {\n if (typeof arg === \"object\") {\n switch (arg.type) {\n case \"repo-relative-file\":\n return path.normalize(\n path.relative(cwd, path.join(repoRoot, arg.path))\n );\n\n case \"succeedable-revset\":\n return `max(successors(${arg.revset}))`;\n }\n }\n return arg;\n });\n }\n\n /**\n * Called by this.operationQueue in response to runOrQueueOperation when an operation is ready to actually run.\n */\n private async runOperation(\n operation: {\n id: string;\n args: Array<CommandArg>;\n stdin?: string;\n },\n onProgress: OperationCommandProgressReporter,\n cwd: string,\n signal: AbortSignal\n ): Promise<void> {\n const cwdRelativeArgs = this.normalizeOperationArgs(cwd, operation.args);\n const { stdin } = operation;\n const { command, args, options } = getExecParams(\n this.info.command,\n cwdRelativeArgs,\n cwd,\n stdin ? { input: stdin } : undefined\n );\n\n this.logger.log(\"run operation: \", command, cwdRelativeArgs.join(\" \"));\n\n const execution = execa(command, args, {\n ...options,\n stdout: \"pipe\",\n stderr: \"pipe\",\n });\n // It would be more appropriate to call this in reponse to execution.on('spawn'), but\n // this seems to be inconsistent about firing in all versions of node.\n // Just send spawn immediately. Errors during spawn like ENOENT will still be reported by `exit`.\n onProgress(\"spawn\");\n execution.stdout?.on(\"data\", (data) => {\n onProgress(\"stdout\", data.toString());\n });\n execution.stderr?.on(\"data\", (data) => {\n onProgress(\"stderr\", data.toString());\n });\n void execution.on(\"exit\", (exitCode) => {\n onProgress(\"exit\", exitCode || 0);\n });\n signal.addEventListener(\"abort\", () => {\n this.logger.log(\"kill operation: \", command, cwdRelativeArgs.join(\" \"));\n });\n handleAbortSignalOnProcess(execution, signal);\n await execution;\n }\n\n setPageFocus(page: string, state: PageVisibility) {\n this.pageFocusTracker.setState(page, state);\n }\n\n /** Return the latest fetched value for UncommittedChanges. */\n getUncommittedChanges(): FetchedUncommittedChanges | null {\n return this.uncommittedChanges;\n }\n\n subscribeToUncommittedChanges(\n callback: (result: FetchedUncommittedChanges) => unknown\n ): Disposable {\n this.uncommittedChangesEmitter.on(\"change\", callback);\n return {\n dispose: () => {\n this.uncommittedChangesEmitter.off(\"change\", callback);\n },\n };\n }\n\n fetchUncommittedChanges = serializeAsyncCall(async () => {\n const fetchStartTimestamp = Date.now();\n try {\n this.uncommittedChangesBeginFetchingEmitter.emit(\"start\");\n const proc = await this.runCommand([\"internal-only\", \"status\"]);\n const files = (JSON.parse(proc.stdout) as Status).files.map((change) => ({\n ...change,\n path: removeLeadingPathSep(change.path),\n }));\n\n this.uncommittedChanges = {\n fetchStartTimestamp,\n fetchCompletedTimestamp: Date.now(),\n files: { value: files },\n };\n this.uncommittedChangesEmitter.emit(\"change\", this.uncommittedChanges);\n } catch (err) {\n this.logger.error(\"Error fetching files: \", err);\n if (isProcessError(err)) {\n if (err.stderr.includes(\"checkout is currently in progress\")) {\n this.logger.info(\n \"Ignoring `hg status` error caused by in-progress checkout\"\n );\n return;\n }\n }\n // emit an error, but don't save it to this.uncommittedChanges\n this.uncommittedChangesEmitter.emit(\"change\", {\n fetchStartTimestamp,\n fetchCompletedTimestamp: Date.now(),\n files: { error: err instanceof Error ? err : new Error(err as string) },\n });\n }\n });\n\n /** Return the latest fetched value for SmartlogCommits. */\n getSmartlogCommits(): FetchedCommits | null {\n return this.smartlogCommits;\n }\n\n subscribeToSmartlogCommitsChanges(\n callback: (result: FetchedCommits) => unknown\n ) {\n this.smartlogCommitsChangesEmitter.on(\"change\", callback);\n return {\n dispose: () => {\n this.smartlogCommitsChangesEmitter.off(\"change\", callback);\n },\n };\n }\n\n subscribeToSmartlogCommitsBeginFetching(\n callback: (isFetching: boolean) => unknown\n ) {\n const onStart = () => callback(true);\n this.smartlogCommitsBeginFetchingEmitter.on(\"start\", onStart);\n return {\n dispose: () => {\n this.smartlogCommitsBeginFetchingEmitter.off(\"start\", onStart);\n },\n };\n }\n\n subscribeToUncommittedChangesBeginFetching(\n callback: (isFetching: boolean) => unknown\n ) {\n const onStart = () => callback(true);\n this.uncommittedChangesBeginFetchingEmitter.on(\"start\", onStart);\n return {\n dispose: () => {\n this.uncommittedChangesBeginFetchingEmitter.off(\"start\", onStart);\n },\n };\n }\n\n fetchSmartlogCommits = serializeAsyncCall(async () => {\n const fetchStartTimestamp = Date.now();\n try {\n this.smartlogCommitsBeginFetchingEmitter.emit(\"start\");\n const proc = await this.runCommand([\"internal-only\", \"log\"]);\n const commits = parseCommitInfoOutput(this.logger, proc.stdout.trim());\n if (commits.length === 0) {\n throw new Error(ErrorShortMessages.NoCommitsFetched);\n }\n this.smartlogCommits = {\n fetchStartTimestamp,\n fetchCompletedTimestamp: Date.now(),\n commits: { value: commits },\n };\n this.smartlogCommitsChangesEmitter.emit(\"change\", this.smartlogCommits);\n } catch (err) {\n this.logger.error(\"Error fetching commits: \", err);\n this.smartlogCommitsChangesEmitter.emit(\"change\", {\n fetchStartTimestamp,\n fetchCompletedTimestamp: Date.now(),\n commits: {\n error: err instanceof Error ? err : new Error(err as string),\n },\n });\n }\n });\n\n /** Watch for changes to the head commit, e.g. from checking out a new commit */\n subscribeToHeadCommit(callback: (head: BranchInfo) => unknown) {\n let headCommit = this.smartlogCommits?.commits.value?.find(\n (commit) => commit.isHead\n );\n if (headCommit != null) {\n callback(headCommit);\n }\n const onData = (data: FetchedCommits) => {\n const newHead = data?.commits.value?.find((commit) => commit.isHead);\n if (newHead != null && newHead.branch !== headCommit?.branch) {\n callback(newHead);\n headCommit = newHead;\n }\n };\n this.smartlogCommitsChangesEmitter.on(\"change\", onData);\n return {\n dispose: () => {\n this.smartlogCommitsChangesEmitter.off(\"change\", onData);\n },\n };\n }\n\n private catLimiter = new RateLimiter(MAX_SIMULTANEOUS_CAT_CALLS, (s) =>\n this.logger.info(\"[cat]\", s)\n );\n /** Return file content at a given revset, e.g. hash or `.` */\n public cat(file: AbsolutePath, comparison: Comparison): Promise<string> {\n const relativePath = path.relative(this.info.repoRoot, file);\n\n return this.catLimiter.enqueueRun(async () => {\n // For `gt cat`, we want the output of the command verbatim.\n const options = { stripFinalNewline: false };\n return (\n await this.runCommand(\n [\n \"internal-only\",\n \"relative-cat\",\n ...this.catArgs(comparison, relativePath),\n ],\n /*cwd=*/ undefined,\n options\n )\n ).stdout;\n });\n }\n\n private catArgs(comparison: Comparison, file: string): Array<string> {\n switch (comparison.type) {\n case ComparisonType.UncommittedChanges:\n return [\"uncommitted\", file];\n\n case ComparisonType.HeadChanges:\n return [\"head\", file];\n\n case ComparisonType.StackChanges:\n return [\"stack\", file];\n\n case ComparisonType.Committed:\n return [\"stack\", file, \"--ref\", comparison.hash];\n }\n }\n\n public getAllDiffIds(): Array<PRNumber> {\n return (\n this.getSmartlogCommits()\n ?.commits.value?.map((commit) => commit.pr?.number)\n .filter(notEmpty) ?? []\n );\n }\n\n public runCommand(\n args: Array<string>,\n cwd?: string,\n options?: execa.Options\n ): execa.ExecaChildProcess<string> {\n return runCommand({\n command: this.info.command,\n args,\n logger: this.logger,\n cwd: unwrap(cwd ?? this.info.repoRoot),\n options,\n });\n }\n\n public getConfig(configName: string): Promise<string | undefined> {\n return getConfig(\n this.info.command,\n this.logger,\n this.info.repoRoot,\n configName\n );\n }\n public setConfig(\n level: ConfigLevel,\n configName: string,\n configValue: string\n ): Promise<void> {\n return setConfig({\n command: this.info.command,\n logger: this.logger,\n cwd: this.info.repoRoot,\n level,\n configName,\n configValue,\n });\n }\n}\n\nexport function runCommand({\n command: command_,\n args: args_,\n logger,\n cwd,\n options: options_,\n}: {\n command?: string;\n args: Array<string>;\n logger?: Logger;\n cwd: string;\n options?: execa.Options;\n}): execa.ExecaChildProcess {\n const { command, args, options } = getExecParams(\n command_,\n args_,\n cwd,\n options_\n );\n if (logger) {\n logger.log(\"run command: \", command, ...args, options);\n }\n\n return execa(command, args, options);\n}\n\nasync function findVersion(\n command: string | undefined,\n logger: Logger,\n cwd: string\n): Promise<string> {\n try {\n return (\n await runCommand({\n command,\n args: [\"--version\"],\n logger,\n cwd,\n })\n ).stdout;\n } catch (error) {\n logger.error(`Failed to find gt version in ${cwd}`, error);\n throw error;\n }\n}\n\nasync function findRepoInfo(\n command: string | undefined,\n logger: Logger,\n cwd: string\n): Promise<RepoInfoFromCLI | undefined> {\n try {\n return JSON.parse(\n (\n await runCommand({\n command,\n args: [\"internal-only\", \"repo-info\"],\n logger,\n cwd,\n })\n ).stdout\n );\n } catch (error) {\n logger.error(`Failed to find repository info in ${cwd}`, error);\n return undefined;\n }\n}\n\nasync function findRepoProfile(\n command: string | undefined,\n logger: Logger,\n cwd: string\n): Promise<{\n appUrl: string;\n}> {\n try {\n return JSON.parse(\n (\n await runCommand({\n command,\n args: [\"internal-only\", \"profile\"],\n logger,\n cwd,\n })\n ).stdout\n );\n } catch (error) {\n logger.error(`Failed to find repository profile in ${cwd}`, error);\n return {\n appUrl: \"https://app.graphite.dev/\",\n };\n }\n}\n\nasync function getConfig(\n command: string | undefined,\n logger: Logger,\n cwd: string,\n configName: string\n): Promise<string | undefined> {\n try {\n return (\n await runCommand({\n command,\n args: [\"internal-only\", \"config\", configName],\n logger,\n cwd,\n })\n ).stdout.trim();\n } catch {\n // `config` exits with status 1 if config is not set. This is not an error.\n return undefined;\n }\n}\n\n// Eventually add repo\ntype ConfigLevel = \"user\";\nasync function setConfig({\n command,\n logger,\n cwd,\n level,\n configName,\n configValue,\n}: {\n command?: string;\n logger: Logger;\n cwd: string;\n level: ConfigLevel;\n configName: string;\n configValue: string;\n}): Promise<void> {\n await runCommand({\n command,\n args: [\n \"internal-only\",\n \"set-config\",\n `--level`,\n level,\n configName,\n configValue,\n ],\n logger,\n cwd,\n });\n}\n\nfunction getExecParams(\n command: string | undefined,\n args_: Array<string>,\n cwd: string,\n options_?: execa.Options\n): {\n command: string;\n args: Array<string>;\n options: execa.Options;\n} {\n let args = [...args_];\n // expandHomeDir is not supported on windows\n if (process.platform !== \"win32\") {\n // commit/amend have unconventional ways of escaping slashes from messages.\n // We have to 'unescape' to make it work correctly.\n args = args.map((arg) => arg.replace(/\\\\\\\\/g, \"\\\\\"));\n }\n const options = {\n ...options_,\n env: {\n LANG: \"en_US.utf-8\", // make sure to use unicode if user hasn't set LANG themselves\n EDITOR: undefined,\n GRAPHITE_INTERACTIVE: \"true\",\n },\n cwd,\n };\n\n // Hack: for pkg'd CLI, pointing to the executable at itself doesn't work. We need to treat it like a node script.\n if (!command && process.argv[1].startsWith(\"/snapshot/\")) {\n command = process.argv[0];\n args = [\"/snapshot/monologue/apps/public/cli/dist/graphite.js\", ...args];\n } else if (!command) {\n command = \"gt\";\n }\n\n // TODO: we could run with systemd for better OOM protection when on linux\n return { command, args, options };\n}\n\n/**\n * Extract CommitInfos from log calls that use FETCH_TEMPLATE.\n */\nexport function parseCommitInfoOutput(\n logger: Logger,\n output: string\n): SmartlogCommits {\n let commitInfos: Array<BranchInfo> = [];\n try {\n commitInfos = JSON.parse(output);\n } catch (err) {\n logger.error(\"failed to parse branch info\", err);\n }\n return commitInfos;\n}\nexport function parseSuccessorData(\n successorData: string\n): SuccessorInfo | undefined {\n const [successorString] = successorData.split(\",\", 1); // we're only interested in the first available mutation\n if (!successorString) {\n return undefined;\n }\n const successor = successorString.split(\":\");\n return {\n hash: successor[1],\n type: successor[0],\n };\n}\n\n/**\n * Returns absolute path for a repo-relative file path.\n * If the path \"escapes\" the repository's root dir, returns null\n * Used to validate that a file path does not \"escape\" the repo, and the file can safely be modified on the filesystem.\n * absolutePathForFileInRepo(\"foo/bar/file.txt\", repo) -> /path/to/repo/foo/bar/file.txt\n * absolutePathForFileInRepo(\"../file.txt\", repo) -> null\n */\nexport function absolutePathForFileInRepo(\n filePath: RepoRelativePath,\n repo: Repository,\n pathMod = path\n): AbsolutePath | null {\n // Note that resolve() is contractually obligated to return an absolute path.\n const fullPath = pathMod.resolve(repo.info.repoRoot, filePath);\n // Prefix checks on paths can be footguns on Windows for C:\\\\ vs c:\\\\, but since\n // we use the same exact path check here and in the resolve, there should be\n // no incompatibility here.\n if (fullPath.startsWith(repo.info.repoRoot + pathMod.sep)) {\n return fullPath;\n } else {\n return null;\n }\n}\n\nexport function repoRelativePathForAbsolutePath(\n absolutePath: AbsolutePath,\n repo: Repository,\n pathMod = path\n): RepoRelativePath {\n return pathMod.relative(repo.info.repoRoot, absolutePath);\n}\n\nfunction isProcessError(s: unknown): s is { stderr: string } {\n return s != null && typeof s === \"object\" && \"stderr\" in s;\n}\n\nfunction computeNewConflicts(\n previousConflicts: MergeConflicts,\n commandOutput: Status,\n fetchStartTimestamp: number\n): MergeConflicts | undefined {\n const newConflictData = commandOutput;\n if (!newConflictData?.conflicts) {\n return undefined;\n }\n\n const newConflicts = newConflictData.files.filter(\n (file) => file.status === \"UNRESOLVED\"\n );\n const conflicts: MergeConflicts = {\n state: \"loaded\",\n files: [],\n fetchStartTimestamp,\n fetchCompletedTimestamp: Date.now(),\n };\n if (previousConflicts?.files != null && previousConflicts.files.length > 0) {\n // we saw conflicts before, some of which might now be resolved. Preserve previous ordering.\n const newConflictSet = new Set(\n newConflicts.map((conflict) => conflict.path)\n );\n conflicts.files = previousConflicts.files.map((conflict) =>\n newConflictSet.has(conflict.path)\n ? { path: conflict.path, status: \"UNRESOLVED\" }\n : // 'R' is overloaded to mean \"removed\" for `gt status` but 'Resolved' for `gt resolve --list`\n // let's re-write this to make the UI layer simpler.\n { path: conflict.path, status: \"RESOLVED\" }\n );\n } else {\n conflicts.files = newConflicts.map((conflict) => ({\n path: conflict.path,\n status: \"UNRESOLVED\",\n }));\n }\n\n return conflicts;\n}\n","import fs from \"fs\";\nimport path from \"path\";\n\n/**\n * Check if file path exists.\n * May still throw non-ENOENT fs access errors.\n * Note: this works on Node 10.x\n */\nexport function exists(file: string): Promise<boolean> {\n return fs.promises\n .stat(file)\n .then(() => true)\n .catch((error: NodeJS.ErrnoException) => {\n if (error.code === \"ENOENT\") {\n return false;\n } else {\n throw error;\n }\n });\n}\n\n/**\n * Add a trailing path sep (/ or \\) if one does not exist\n */\nexport function ensureTrailingPathSep(p: string): string {\n if (p.endsWith(path.sep)) {\n return p;\n }\n return p + path.sep;\n}\n\n/**\n * Add a trailing path sep (/ or \\) if one does not exist\n */\nexport function removeLeadingPathSep(p: string): string {\n if (p.startsWith(path.sep)) {\n return p.slice(1);\n }\n return p;\n}\n","import type {\n AbsolutePath,\n PlatformSpecificClientToServerMessages,\n ServerToClientMessage,\n} from \"@withgraphite/gti-shared\";\nimport { unwrap } from \"@withgraphite/gti-shared\";\nimport { spawn } from \"child_process\";\nimport pathModule from \"path\";\n\nimport type { Repository } from \"./Repository\";\n\n/**\n * Platform-specific server-side API for each target: vscode extension host, electron standalone, browser, ...\n * See also platform.ts\n */\nexport interface ServerPlatform {\n platformName: string;\n handleMessageFromClient(\n repo: Repository | undefined,\n message: PlatformSpecificClientToServerMessages,\n postMessage: (message: ServerToClientMessage) => void,\n onDispose: (disapose: () => unknown) => void\n ): void | Promise<void>;\n}\n\nexport const browserServerPlatform: ServerPlatform = {\n platformName: \"browser\",\n handleMessageFromClient: (\n repo: Repository | undefined,\n message: PlatformSpecificClientToServerMessages\n ) => {\n switch (message.type) {\n case \"platform/openFile\": {\n const path: AbsolutePath = pathModule.join(\n unwrap(repo?.info.repoRoot),\n message.path\n );\n let command;\n if (command == null) {\n // use OS-builtin open command to open files\n // (which may open different file extensions with different programs)\n // TODO: add a config option to determine which program to launch\n switch (process.platform) {\n case \"darwin\":\n command = \"/usr/bin/open\";\n break;\n\n case \"win32\":\n command = \"notepad.exe\";\n break;\n\n case \"linux\":\n command = \"xdg-open\";\n break;\n\n default:\n }\n }\n if (command) {\n // Because the GTI server is likely running in the background and is\n // no longer attached to a terminal, this is designed for the case\n // where the user opens the file in a windowed editor (hence\n // `windowsHide: false`, which is the default for\n // `child_process.spawn()`, but not for `execa()`):\n //\n // - For users using a simple one-window-per-file graphical text\n // editor, like notepad.exe, this is relatively straightforward.\n // - For users who prefer a terminal-based editor, like Emacs,\n // a conduit like EmacsClient would be required.\n //\n // Further, killing GTI should not kill the editor, so this follows\n // the pattern for spawning an independent, long-running process in\n // Node.js as described here:\n //\n // https://nodejs.org/docs/latest-v10.x/api/child_process.html#child_process_options_detached\n repo?.logger.log(\"open file\", path);\n // TODO: Report error if spawn() fails?\n const proc = spawn(command, [path], {\n detached: true,\n stdio: \"ignore\",\n windowsHide: false,\n windowsVerbatimArguments: true,\n });\n // Silent error. Don't crash the server process.\n proc.on(\"error\", (err) => {\n repo?.logger.log(\"failed to open\", path, err);\n });\n proc.unref();\n }\n break;\n }\n\n default:\n }\n },\n};\n","import type {\n AbsolutePath,\n Logger,\n RepositoryError,\n ValidatedRepoInfo,\n} from \"@withgraphite/gti-shared\";\n\nimport { ensureTrailingPathSep } from \"./fs\";\nimport { Repository } from \"./Repository\";\nimport { TypedEventEmitter } from \"./TypedEventEmitter\";\n\n/**\n * Reference-counting access to a {@link Repository}, via a Promise.\n * Be sure to `unref()` when no longer needed.\n */\nexport interface RepositoryReference {\n promise: Promise<Repository | RepositoryError>;\n unref: () => unknown;\n}\n\n/**\n * We return `RepositoryReference`s synchronously before we have the Repository,\n * but reference counts should be associated with the actual async constructed Repository,\n * which is why we can't return RefCounted<Repository> directly.\n */\nclass RepositoryReferenceImpl implements RepositoryReference {\n constructor(\n public promise: Promise<Repository | RepositoryError>,\n private disposeFunc: () => void\n ) {}\n public unref() {\n if (!this.disposed) {\n this.disposed = true;\n this.disposeFunc();\n }\n }\n\n internalReference: RefCounted<Repository> | undefined;\n disposed = false;\n}\n\nclass RefCounted<T extends { dispose: () => void }> {\n constructor(public value: T) {}\n private references = 0;\n\n public isDisposed = false;\n public ref() {\n this.references++;\n }\n public getNumberOfReferences() {\n return this.references;\n }\n public dispose() {\n this.references--;\n if (!this.isDisposed && this.references === 0) {\n this.isDisposed = true;\n this.value.dispose();\n }\n }\n}\n\n/**\n * Allow re-using Repository instances by storing instances by path,\n * and controlling how Repositories are created.\n *\n * Some async work is needed to construct repositories (finding repo root dir),\n * so it's possible to duplicate some work if multiple repos are constructed at similar times.\n * We still enable Repository re-use in this case by double checking for pre-existing Repos at the last second.\n */\nclass RepositoryCache {\n // allow mocking Repository in tests\n constructor(private RepositoryType = Repository) {}\n\n /**\n * Previously distributed RepositoryReferences, keyed by repository root path\n * Note that Repositories do not define their own `cwd`, and can be re-used across cwds.\n */\n private reposByRoot = new Map<AbsolutePath, RefCounted<Repository>>();\n private activeReposEmitter = new TypedEventEmitter<\"change\", undefined>();\n\n private lookup(dirGuess: AbsolutePath): RefCounted<Repository> | undefined {\n for (const repo of this.reposByRoot.values()) {\n if (\n dirGuess === repo.value.info.repoRoot ||\n dirGuess.startsWith(ensureTrailingPathSep(repo.value.info.repoRoot))\n ) {\n if (!repo.isDisposed) {\n return repo;\n }\n }\n }\n return undefined;\n }\n\n /**\n * Create a new Repository, or re-use if one already exists.\n * Repositories are reference-counted to ensure they can be disposed when no longer needed.\n */\n getOrCreate(\n cmd: string | undefined,\n logger: Logger,\n cwd: string\n ): RepositoryReference {\n // Fast path: if this cwd is already a known repo root, we can use it directly.\n // This only works if the cwd happens to be the repo root.\n const found = this.lookup(cwd);\n if (found) {\n found.ref();\n return new RepositoryReferenceImpl(Promise.resolve(found.value), () =>\n found.dispose()\n );\n }\n\n // More typically, we can re-use a Repository among different cwds:\n\n // eslint-disable-next-line prefer-const\n let ref: RepositoryReferenceImpl;\n const lookupRepoInfoAndReuseIfPossible = async (): Promise<\n Repository | RepositoryError\n > => {\n // TODO: we should rate limit how many getRepoInfos we run at a time, and make other callers just wait.\n // this would guard against querying lots of redundant paths within the same repo.\n // This is probably not necessary right now, but would be useful for a VS Code extension where we need to query\n // individual file paths to add diff gutters.\n const repoInfo = await this.RepositoryType.getRepoInfo(cmd, logger, cwd);\n // important: there should be no `await` points after here, to ensure there is no race when re-using Repositories.\n if (repoInfo.type !== \"success\") {\n // No repository found at this root, or some other error prevents the repo from being created\n return repoInfo;\n }\n\n if (ref.disposed) {\n // If the reference is disposed, the caller gave up while waiting for the repo to be created.\n // make sure we don't create a dangling Repository.\n return {\n type: \"unknownError\",\n error: new Error(\"Repository already disposed\"),\n };\n }\n\n // Now that we've spent some async time to determine this repo's actual root,\n // we can check if we already have a reference to it saved.\n // This way, we can still re-use a Repository, and only risk duplicating `getRepoInfo` work.\n const newlyFound = this.lookup(repoInfo.repoRoot);\n if (newlyFound) {\n // if it is found now, it means either the cwd differs from the repo root (lookup fails), or\n // another instance was created at the same time and finished faster than this one (lookup failed before, but succeeds now).\n\n newlyFound.ref();\n ref.internalReference = newlyFound;\n return newlyFound.value;\n }\n\n // This is where we actually start new subscriptions and trigger work, so we should only do this\n // once we're sure we don't have a repository to re-use.\n const repo = new this.RepositoryType(\n repoInfo as ValidatedRepoInfo, // repoInfo is now guaranteed to have these root/dotdir set\n logger\n );\n\n const internalRef = new RefCounted(repo);\n internalRef.ref();\n ref.internalReference = internalRef;\n this.reposByRoot.set(repoInfo.repoRoot, internalRef);\n this.activeReposEmitter.emit(\"change\");\n return repo;\n };\n ref = new RepositoryReferenceImpl(\n lookupRepoInfoAndReuseIfPossible(),\n () => {\n if (ref.internalReference) {\n ref.internalReference.dispose();\n }\n ref.unref();\n }\n );\n return ref;\n }\n\n /**\n * Lookup a cached repository without creating a new one if it doens't exist\n */\n public cachedRepositoryForPath(path: AbsolutePath): Repository | undefined {\n const ref = this.lookup(path);\n return ref?.value;\n }\n\n public onChangeActiveRepos(\n cb: (repos: Array<Repository>) => unknown\n ): () => unknown {\n const onChange = () => {\n cb([...this.reposByRoot.values()].map((ref) => ref.value));\n };\n this.activeReposEmitter.on(\"change\", onChange);\n // start with initial repos set\n onChange();\n return () => this.activeReposEmitter.off(\"change\", onChange);\n }\n\n /** Clean up all known repos. Mostly useful for testing. */\n clearCache() {\n this.reposByRoot.forEach((value) => value.dispose());\n this.reposByRoot = new Map();\n this.activeReposEmitter.removeAllListeners();\n }\n\n public numberOfActiveServers(): number {\n let numActive = 0;\n for (const repo of this.reposByRoot.values()) {\n numActive += repo.getNumberOfReferences();\n }\n return numActive;\n }\n}\n\nexport const __TEST__ = { RepositoryCache };\n\nexport const repositoryCache = new RepositoryCache();\n","import type { ChangedFiles } from \"@withgraphite/gti-cli-shared-types\";\nimport type {\n ClientToServerMessage,\n ClientToServerMessageWithPayload,\n Disposable,\n FetchedCommits,\n FetchedUncommittedChanges,\n Logger,\n MergeConflicts,\n PlatformSpecificClientToServerMessages,\n RepositoryError,\n Result,\n ServerToClientMessage,\n} from \"@withgraphite/gti-shared\";\nimport {\n deserializeFromString,\n randomId,\n revsetArgsForComparison,\n serializeToString,\n unwrap,\n} from \"@withgraphite/gti-shared\";\nimport fs from \"fs\";\n\nimport type { ClientConnection } from \".\";\nimport type { ServerSideTracker } from \"./analytics/serverSideTracker\";\nimport { absolutePathForFileInRepo, Repository } from \"./Repository\";\nimport type { RepositoryReference } from \"./RepositoryCache\";\nimport { repositoryCache } from \"./RepositoryCache\";\nimport type { ServerPlatform } from \"./serverPlatform\";\nimport { findPublicAncestor } from \"./utils\";\n\ntype IncomingMessageWithPayload = ClientToServerMessageWithPayload;\nexport type IncomingMessage = ClientToServerMessage;\nexport type OutgoingMessage = ServerToClientMessage;\n\ntype GeneralMessage = IncomingMessage &\n (\n | { type: \"changeCwd\" }\n | { type: \"requestRepoInfo\" }\n | { type: \"requestApplicationInfo\" }\n | { type: \"fileBugReport\" }\n | { type: \"track\" }\n );\ntype WithRepoMessage = Exclude<IncomingMessage, GeneralMessage>;\n\n/**\n * Return true if a ClientToServerMessage is a ClientToServerMessageWithPayload\n */\nfunction expectsBinaryPayload(\n message: unknown\n): message is ClientToServerMessageWithPayload {\n return (\n message != null &&\n typeof message === \"object\" &&\n (message as ClientToServerMessageWithPayload).hasBinaryPayload === true\n );\n}\n\n/**\n * Message passing channel built on top of ClientConnection.\n * Use to send and listen for well-typed events with the client\n *\n * Note: you must set the current repository to start sending data back to the client.\n */\nexport class ServerToClientAPI {\n private listenersByType = new Map<\n string,\n Set<(message: IncomingMessage) => void | Promise<void>>\n >();\n private incomingListener: Disposable;\n\n /** Disposables that must be disposed whenever the current repo is changed */\n private repoDisposables: Array<Disposable> = [];\n private subscriptions = new Map<string, Disposable>();\n private activeRepoRef: RepositoryReference | undefined;\n\n private queuedMessages: Array<IncomingMessage> = [];\n private currentState:\n | { type: \"loading\" }\n | { type: \"repo\"; repo: Repository; cwd: string }\n | { type: \"error\"; error: RepositoryError } = { type: \"loading\" };\n\n private pageId = randomId();\n\n constructor(\n private platform: ServerPlatform,\n private connection: ClientConnection,\n private tracker: ServerSideTracker,\n private logger: Logger\n ) {\n // messages with binary payloads are sent as two post calls. We first get the JSON message, then the binary payload,\n // which we will reconstruct together.\n let messageExpectingBinaryFollowup: ClientToServerMessageWithPayload | null =\n null;\n this.incomingListener = this.connection.onDidReceiveMessage(\n (buf, isBinary) => {\n if (isBinary) {\n if (messageExpectingBinaryFollowup == null) {\n connection.logger?.error(\n \"Error: got a binary message when not expecting one\"\n );\n return;\n }\n // TODO: we don't handle queueing up messages with payloads...\n this.handleIncomingMessageWithPayload(\n messageExpectingBinaryFollowup,\n buf\n );\n messageExpectingBinaryFollowup = null;\n return;\n } else if (messageExpectingBinaryFollowup != null) {\n connection.logger?.error(\n \"Error: didnt get binary payload after a message that requires one\"\n );\n messageExpectingBinaryFollowup = null;\n return;\n }\n const message = buf.toString(\"utf-8\");\n const data = deserializeFromString(message) as IncomingMessage;\n if (expectsBinaryPayload(data)) {\n // remember this message, and wait to get the binary payload before handling it\n messageExpectingBinaryFollowup = data;\n return;\n }\n\n // When the client is connected, we want to immediately start listening to messages.\n // However, we can't properly respond to these messages until we have a repository set up.\n // Queue up messages until a repository is set.\n if (this.currentState.type === \"loading\") {\n this.queuedMessages.push(data);\n } else {\n try {\n this.handleIncomingMessage(data);\n } catch (err) {\n connection.logger?.error(\n \"error handling incoming message: \",\n data,\n err\n );\n }\n }\n }\n );\n }\n\n private setRepoError(error: RepositoryError) {\n this.disposeRepoDisposables();\n\n this.currentState = { type: \"error\", error };\n\n this.tracker.context.setRepo(undefined);\n\n this.processQueuedMessages();\n }\n\n private setCurrentRepo(repo: Repository, cwd: string) {\n this.disposeRepoDisposables();\n\n this.currentState = { type: \"repo\", repo, cwd };\n\n this.tracker.context.setRepo(repo);\n\n if (repo.codeReviewProvider != null) {\n this.repoDisposables.push(\n repo.codeReviewProvider.onChangeDiffSummaries((value) => {\n this.postMessage({ type: \"fetchedDiffSummaries\", summaries: value });\n })\n );\n }\n\n this.repoDisposables.push(\n repo.subscribeToHeadCommit((head) => {\n const allCommits = repo.getSmartlogCommits();\n const ancestor = findPublicAncestor(allCommits?.commits.value, head);\n this.tracker.track(\"HeadCommitChanged\", {\n extras: {\n hash: head.branch,\n public: ancestor?.branch,\n },\n });\n })\n );\n\n this.processQueuedMessages();\n }\n\n postMessage(message: OutgoingMessage) {\n void this.connection.postMessage(serializeToString(message)).catch(() => {\n // eslint-disable-next-line no-console\n console.warn(\"Failed to post message to client\");\n });\n }\n\n /** Get a repository reference for a given cwd, and set that as the active repo. */\n setActiveRepoForCwd(newCwd: string) {\n if (this.activeRepoRef !== undefined) {\n this.activeRepoRef.unref();\n }\n this.logger.info(`Setting active repo cwd to ${newCwd}`);\n // Set as loading right away while we determine the new cwd's repo\n // This ensures new messages coming in will be queued and handled only with the new repository\n this.currentState = { type: \"loading\" };\n const command = this.connection.command;\n this.activeRepoRef = repositoryCache.getOrCreate(\n command,\n this.logger,\n newCwd\n );\n void this.activeRepoRef.promise.then((repoOrError) => {\n if (repoOrError instanceof Repository) {\n this.setCurrentRepo(repoOrError, newCwd);\n } else {\n this.setRepoError(repoOrError);\n }\n });\n }\n\n dispose() {\n this.incomingListener.dispose();\n this.disposeRepoDisposables();\n\n if (this.activeRepoRef !== undefined) {\n this.activeRepoRef.unref();\n }\n }\n\n private disposeRepoDisposables() {\n this.repoDisposables.forEach((disposable) => disposable.dispose());\n this.repoDisposables = [];\n\n this.subscriptions.forEach((sub) => sub.dispose());\n this.subscriptions.clear();\n }\n\n private processQueuedMessages() {\n for (const message of this.queuedMessages) {\n try {\n this.handleIncomingMessage(message);\n } catch (err) {\n this.connection.logger?.error(\n \"error handling queued message: \",\n message,\n err\n );\n }\n }\n this.queuedMessages = [];\n }\n\n private handleIncomingMessageWithPayload(\n message: IncomingMessageWithPayload,\n payload: ArrayBuffer\n ) {\n switch (message.type) {\n case \"uploadFile\": {\n const { id, filename } = message;\n const uploadFile: null | ((value: any, opts: any) => Promise<string>) =\n null as null | ((value: any) => Promise<string>);\n if (uploadFile == null) {\n return;\n }\n this.tracker\n .operation(\"UploadImage\", \"UploadImageError\", {}, () =>\n uploadFile(unwrap(this.connection.logger), {\n filename,\n data: payload,\n })\n )\n .then((result: string) => {\n this.connection.logger?.info(\n \"sucessfully uploaded file\",\n filename,\n result\n );\n this.postMessage({\n type: \"uploadFileResult\",\n id,\n result: { value: result },\n });\n })\n .catch((error: Error) => {\n this.connection.logger?.info(\n \"error uploading file\",\n filename,\n error\n );\n this.postMessage({\n type: \"uploadFileResult\",\n id,\n result: { error },\n });\n });\n break;\n }\n }\n }\n\n private handleIncomingMessage(data: IncomingMessage) {\n this.handleIncomingGeneralMessage(data as GeneralMessage);\n const { currentState } = this;\n switch (currentState.type) {\n case \"repo\": {\n const { repo, cwd } = currentState;\n this.handleIncomingMessageWithRepo(data as WithRepoMessage, repo, cwd);\n break;\n }\n\n // If the repo is in the loading or error state, the client may still send\n // platform messages such as `platform/openExternal` that should be processed.\n case \"loading\":\n case \"error\":\n if (data.type.startsWith(\"platform/\")) {\n void this.platform.handleMessageFromClient(\n /*repo=*/ undefined,\n data as PlatformSpecificClientToServerMessages,\n (message) => this.postMessage(message),\n (dispose: () => unknown) => {\n this.repoDisposables.push({ dispose });\n }\n );\n this.notifyListeners(data);\n }\n break;\n }\n }\n\n /**\n * Handle messages which can be handled regardless of if a repo was successfully created or not\n */\n private handleIncomingGeneralMessage(data: GeneralMessage) {\n switch (data.type) {\n case \"track\": {\n this.tracker.trackData(data.data);\n break;\n }\n\n case \"changeCwd\": {\n this.setActiveRepoForCwd(data.cwd);\n break;\n }\n\n case \"requestRepoInfo\": {\n switch (this.currentState.type) {\n case \"repo\":\n this.postMessage({\n type: \"repoInfo\",\n info: this.currentState.repo.info,\n cwd: this.currentState.cwd,\n });\n break;\n\n case \"error\":\n this.postMessage({\n type: \"repoInfo\",\n info: this.currentState.error,\n });\n break;\n\n case \"loading\":\n }\n break;\n }\n\n case \"requestApplicationInfo\": {\n this.postMessage({\n type: \"applicationInfo\",\n platformName: this.platform.platformName,\n version: this.connection.version,\n });\n break;\n }\n\n case \"fileBugReport\": {\n // Internal.fileABug?.(\n // data.data,\n // data.uiState,\n // this.tracker,\n // this.logger,\n // (progress: FileABugProgress) => {\n // this.connection.logger?.info('file a bug progress: ', JSON.stringify(progress));\n // this.postMessage({type: 'fileBugReportProgress', ...progress});\n // },\n // );\n break;\n }\n }\n }\n\n /**\n * Handle messages which require a repository to have been successfully set up to run\n */\n private handleIncomingMessageWithRepo(\n data: WithRepoMessage,\n repo: Repository,\n cwd: string\n ) {\n const { logger } = repo;\n switch (data.type) {\n case \"subscribe\": {\n const { subscriptionID, kind } = data;\n switch (kind) {\n case \"uncommittedChanges\": {\n const postUncommittedChanges = (\n result: FetchedUncommittedChanges\n ) => {\n this.postMessage({\n type: \"subscriptionResult\",\n kind: \"uncommittedChanges\",\n subscriptionID,\n data: result,\n });\n };\n\n const uncommittedChanges = repo.getUncommittedChanges();\n if (uncommittedChanges != null) {\n postUncommittedChanges(uncommittedChanges);\n }\n const disposables: Array<Disposable> = [];\n\n // send changes as they come in from watchman\n disposables.push(\n repo.subscribeToUncommittedChanges(postUncommittedChanges)\n );\n // trigger a fetch on startup\n void repo.fetchUncommittedChanges();\n\n disposables.push(\n repo.subscribeToUncommittedChangesBeginFetching(() =>\n this.postMessage({\n type: \"beganFetchingUncommittedChangesEvent\",\n })\n )\n );\n this.subscriptions.set(subscriptionID, {\n dispose: () => {\n disposables.forEach((d) => d.dispose());\n },\n });\n break;\n }\n\n case \"smartlogCommits\": {\n const postSmartlogCommits = (result: FetchedCommits) => {\n this.postMessage({\n type: \"subscriptionResult\",\n kind: \"smartlogCommits\",\n subscriptionID,\n data: result,\n });\n };\n\n const smartlogCommits = repo.getSmartlogCommits();\n if (smartlogCommits != null) {\n postSmartlogCommits(smartlogCommits);\n }\n const disposables: Array<Disposable> = [];\n // send changes as they come from file watcher\n disposables.push(\n repo.subscribeToSmartlogCommitsChanges(postSmartlogCommits)\n );\n // trigger a fetch on startup\n void repo.fetchSmartlogCommits();\n\n disposables.push(\n repo.subscribeToSmartlogCommitsBeginFetching(() =>\n this.postMessage({ type: \"beganFetchingSmartlogCommitsEvent\" })\n )\n );\n\n this.subscriptions.set(subscriptionID, {\n dispose: () => {\n disposables.forEach((d) => d.dispose());\n },\n });\n break;\n }\n\n case \"mergeConflicts\": {\n const postMergeConflicts = (\n conflicts: MergeConflicts | undefined\n ) => {\n this.postMessage({\n type: \"subscriptionResult\",\n kind: \"mergeConflicts\",\n subscriptionID,\n data: conflicts,\n });\n };\n\n const mergeConflicts = repo.getMergeConflicts();\n if (mergeConflicts != null) {\n postMergeConflicts(mergeConflicts);\n }\n\n this.subscriptions.set(\n subscriptionID,\n repo.onChangeConflictState(postMergeConflicts)\n );\n break;\n }\n }\n break;\n }\n\n case \"unsubscribe\": {\n const subscription = this.subscriptions.get(data.subscriptionID);\n subscription?.dispose();\n this.subscriptions.delete(data.subscriptionID);\n break;\n }\n\n case \"runOperation\": {\n const { operation } = data;\n void repo.runOrQueueOperation(\n operation,\n (progress) => {\n this.postMessage({ type: \"operationProgress\", ...progress });\n if (progress.kind === \"queue\") {\n this.tracker.track(\"QueueOperation\", {\n extras: { operation: operation.trackEventName },\n });\n }\n },\n this.tracker,\n cwd\n );\n break;\n }\n\n case \"abortRunningOperation\": {\n const { operationId } = data;\n repo.abortRunningOpeation(operationId);\n break;\n }\n\n case \"getConfig\": {\n void repo\n .getConfig(data.name)\n .catch(() => undefined)\n .then((value) => {\n logger.info(\"got config\", data.name, value);\n this.postMessage({ type: \"gotConfig\", name: data.name, value });\n });\n break;\n }\n\n case \"fetchRepoMessage\": {\n const repoMessage: Promise<Result<string>> = repo\n .runCommand([\"internal-only\", \"repo-message\"])\n .then((o) => ({ value: o.stdout }))\n .catch((error) => {\n logger?.error(\"error fetching repo message\", error.toString());\n return { error };\n });\n void repoMessage.then((data) =>\n this.postMessage({\n type: \"fetchedRepoMessage\",\n message: data.value || \"\",\n })\n );\n break;\n }\n\n case \"fetchUpgradePrompt\": {\n const upgradePrompt: Promise<Result<string>> = repo\n .runCommand([\"internal-only\", \"upgrade-prompt\"])\n .then((o) => ({ value: o.stdout }))\n .catch((error) => {\n logger?.error(\"error fetching upgrade prompt\", error.toString());\n return { error };\n });\n void upgradePrompt.then((data) =>\n this.postMessage({\n type: \"fetchedUpgradePrompt\",\n message: data.value || \"\",\n })\n );\n break;\n }\n\n case \"setConfig\": {\n logger.info(\"set config\", data.name, data.value);\n repo.setConfig(\"user\", data.name, data.value).catch((err) => {\n logger.error(\"error setting config\", data.name, data.value, err);\n });\n break;\n }\n\n case \"deleteFile\": {\n const { filePath } = data;\n const absolutePath = absolutePathForFileInRepo(filePath, repo);\n // security: don't trust client messages to allow us to delete files outside the repository\n if (absolutePath == null) {\n logger.warn(\"can't delete file outside of the repo\", filePath);\n return;\n }\n\n fs.promises\n .rm(absolutePath)\n .then(() => {\n logger.info(\"deleted file from filesystem\", absolutePath);\n })\n .catch((err) => {\n logger.error(\"unable to delete file\", absolutePath, err);\n });\n break;\n }\n\n case \"requestComparison\": {\n const { comparison } = data;\n const diff: Promise<Result<string>> = repo\n .runCommand([\n \"internal-only\",\n \"diff\",\n ...revsetArgsForComparison(comparison),\n ])\n .then((o) => ({ value: o.stdout }))\n .catch((error) => {\n logger?.error(\"error running diff\", error.toString());\n return { error };\n });\n void diff.then((data) =>\n this.postMessage({\n type: \"comparison\",\n comparison,\n data: { diff: data },\n })\n );\n break;\n }\n\n case \"requestChangedFiles\": {\n const { branch } = data;\n const resultPromise: Promise<ChangedFiles> = repo\n .runCommand([\"internal-only\", \"changed-files\", branch])\n .then((o) => JSON.parse(o.stdout))\n .catch((error) => {\n logger?.error(\"error running diff\", error.toString());\n return { error };\n });\n void resultPromise.then((result) =>\n this.postMessage({\n type: \"changedFiles\",\n branch,\n data: result,\n })\n );\n break;\n }\n\n case \"requestComparisonContextLines\": {\n const {\n id: { path: relativePath, comparison },\n start,\n numLines,\n } = data;\n\n // TODO: For context lines, before/after sides of the comparison\n // are identical... except for line numbers.\n // Typical comparisons with '.' would be much faster (nearly instant)\n // by reading from the filesystem rather than using cat,\n // we just need the caller to ask with \"after\" line numbers instead of \"before\".\n // Note: we would still need to fall back to cat for comparisons that do not involve\n // the working copy.\n const cat: Promise<string> = repo\n .cat(relativePath, comparison)\n .catch(() => \"\");\n\n void cat.then((content) =>\n this.postMessage({\n type: \"comparisonContextLines\",\n lines: content.split(\"\\n\").slice(start - 1, start - 1 + numLines),\n path: relativePath,\n })\n );\n break;\n }\n\n case \"refresh\": {\n logger?.log(\"refresh requested\");\n void repo.fetchSmartlogCommits();\n void repo.fetchUncommittedChanges();\n void repo.codeReviewProvider?.triggerDiffSummariesFetch(\n repo.getAllDiffIds()\n );\n break;\n }\n\n case \"pageVisibility\": {\n repo.setPageFocus(this.pageId, data.state);\n break;\n }\n\n case \"fetchCommitMessageTemplate\": {\n repo\n .runCommand([\"internal-only\", \"templates\"])\n .then((result) => {\n const templates: Record<string, string> = JSON.parse(result.stdout);\n this.postMessage({\n type: \"fetchedCommitMessageTemplate\",\n templates: Object.fromEntries(\n Object.entries(templates).map(([path, contents]) => [\n path,\n contents.replace(repo.IGNORE_COMMIT_MESSAGE_LINES_REGEX, \"\"),\n ])\n ),\n });\n })\n .catch((err) => {\n logger?.error(\"Could not fetch commit message template\", err);\n });\n break;\n }\n\n case \"typeahead\": {\n // Current repo's code review provider should be able to handle all\n // TypeaheadKinds for the fields in its defined schema.\n void repo.codeReviewProvider\n ?.typeahead?.(data.kind, data.query)\n ?.then((result) =>\n this.postMessage({\n type: \"typeaheadResult\",\n id: data.id,\n result,\n })\n );\n break;\n }\n\n case \"fetchDiffSummaries\": {\n void repo.codeReviewProvider?.triggerDiffSummariesFetch(\n repo.getAllDiffIds()\n );\n break;\n }\n\n case \"loadMoreCommits\": {\n const rangeInDays = repo.nextVisibleCommitRangeInDays();\n this.postMessage({ type: \"commitsShownRange\", rangeInDays });\n this.postMessage({ type: \"beganLoadingMoreCommits\" });\n void repo.fetchSmartlogCommits();\n this.tracker.track(\"LoadMoreCommits\", {\n extras: { daysToFetch: rangeInDays ?? \"Infinity\" },\n });\n return;\n }\n\n default: {\n void this.platform.handleMessageFromClient(\n repo,\n data,\n (message) => this.postMessage(message),\n (dispose: () => unknown) => {\n this.repoDisposables.push({ dispose });\n }\n );\n break;\n }\n }\n\n this.notifyListeners(data);\n }\n\n private notifyListeners(data: IncomingMessage): void {\n const listeners = this.listenersByType.get(data.type);\n if (listeners) {\n listeners.forEach((handle) => handle(data));\n }\n }\n}\n","import { unwrap } from \"@withgraphite/gti-shared\";\nimport fs from \"fs\";\nimport os from \"os\";\nimport path from \"path\";\n\nimport rmtree from \"./rmtree\";\n\nexport type ExistingServerInfo = {\n sensitiveToken: string;\n challengeToken: string;\n logFileLocation: string;\n /** Which command name was used to launch this server instance,\n * so it can be propagated to run further gt commands by the server.\n * Usually, \"gt\". */\n command?: string;\n /**\n * `gt version` string. If the version of gt changes, we shouldn't re-use that server instance,\n * due to potential incompatibilities between the old running server javascript and the new client javascript.\n */\n gtVersion: string;\n};\n\nconst cacheDir =\n process.platform == \"win32\"\n ? path.join(unwrap(process.env.LOCALAPPDATA), \"cache\")\n : process.platform == \"darwin\"\n ? path.join(os.homedir(), \"Library/Caches\")\n : process.env.XDG_CACHE_HOME || path.join(os.homedir(), \".cache\");\n\n/**\n * Per-user cache dir with restrictive permissions.\n * Inside this folder will be a number of files, one per port for an active GTI server.\n */\nconst savedActiveServerUrlsDirectory = path.join(cacheDir, \"graphite-gti\");\n\nfunction fileNameForPort(port: number): string {\n return `reusable_server_${port}`;\n}\n\nfunction isMode700(stat: fs.Stats): boolean {\n // eslint-disable-next-line no-bitwise\n return (stat.mode & 0o777) === 0o700;\n}\n\n/**\n * Make a temp directory with restrictive permissions where we can write existing server information.\n * Ensures directory has proper restrictive mode if the directory already exists.\n */\nexport async function ensureExistingServerFolder(): Promise<void> {\n await fs.promises.mkdir(savedActiveServerUrlsDirectory, {\n // directory needs rwx\n mode: 0o700,\n recursive: true,\n });\n\n const stat = await fs.promises.stat(savedActiveServerUrlsDirectory);\n if (process.platform !== \"win32\" && !isMode700(stat)) {\n throw new Error(\n `active servers folder ${savedActiveServerUrlsDirectory} has the wrong permissions: ${stat.mode}`\n );\n }\n if (stat.isSymbolicLink()) {\n throw new Error(\n `active servers folder ${savedActiveServerUrlsDirectory} is a symlink`\n );\n }\n}\n\nexport function deleteExistingServerFile(port: number): Promise<void> {\n const folder = path.join(\n savedActiveServerUrlsDirectory,\n fileNameForPort(port)\n );\n if (typeof fs.promises.rm === \"function\") {\n return fs.promises.rm(folder, { force: true });\n } else {\n return rmtree(folder);\n }\n}\n\nexport async function writeExistingServerFile(\n port: number,\n data: ExistingServerInfo\n): Promise<void> {\n await fs.promises.writeFile(\n path.join(savedActiveServerUrlsDirectory, fileNameForPort(port)),\n JSON.stringify(data),\n { encoding: \"utf-8\", flag: \"w\", mode: 0o600 }\n );\n}\n\nexport async function readExistingServerFile(\n port: number\n): Promise<ExistingServerInfo> {\n // TODO: do we need to verify the permissions of this file?\n const data: string = await fs.promises.readFile(\n path.join(savedActiveServerUrlsDirectory, fileNameForPort(port)),\n { encoding: \"utf-8\", flag: \"r\" }\n );\n return JSON.parse(data) as ExistingServerInfo;\n}\n","import { timingSafeEqual } from \"crypto\";\n\n/**\n * Timing safe comparison of tokens coming from strings.\n */\nexport function areTokensEqual(a: string, b: string): boolean {\n const aBuf = Buffer.from(a);\n const bBuf = Buffer.from(b);\n return aBuf.length === bBuf.length && timingSafeEqual(aBuf, bBuf);\n}\n","import type { Logger } from \"@withgraphite/gti-shared\";\n\nimport { makeServerSideTracker } from \"./analytics/serverSideTracker\";\nimport { fileLogger, stdoutLogger } from \"./logger\";\nimport { runCommand } from \"./Repository\";\nimport type { ServerPlatform } from \"./serverPlatform\";\nimport { browserServerPlatform } from \"./serverPlatform\";\nimport { ServerToClientAPI } from \"./ServerToClientAPI\";\n\nexport { DEFAULT_PORT, runProxyMain } from \"../proxy/startServer\";\n\nexport interface ClientConnection {\n /**\n * Used to send a message from the server to the client.\n *\n * Designed to match\n * https://code.visualstudio.com/api/references/vscode-api#Webview.postMessage\n */\n postMessage(message: string): Promise<boolean>;\n\n /**\n * Designed to match\n * https://code.visualstudio.com/api/references/vscode-api#Webview.onDidReceiveMessage\n */\n onDidReceiveMessage(\n hander: (event: Buffer, isBinary: boolean) => void | Promise<void>\n ): {\n dispose(): void;\n };\n\n /**\n * Which command to use to run `gt`\n */\n command?: string;\n /**\n * Platform-specific version string.\n * For `gt interactive web`, this is the `gt` version.\n * For the VS Code extension, this is the extension version.\n */\n version: string;\n logFileLocation?: string;\n logger?: Logger;\n cwd: string;\n\n platform?: ServerPlatform;\n}\n\nexport function onClientConnection(connection: ClientConnection): () => void {\n const logger =\n connection.logger ??\n (connection.logFileLocation\n ? fileLogger(connection.logFileLocation)\n : stdoutLogger);\n connection.logger = logger;\n const platform = connection?.platform ?? browserServerPlatform;\n const version = connection?.version ?? \"unknown\";\n logger.log(`establish client connection for ${connection.cwd}`);\n logger.log(`platform '${platform.platformName}', version '${version}'`);\n\n const tracker = makeServerSideTracker(logger, platform, version, (data) => {\n return runCommand({\n command: connection.command || \"gt\",\n args: [\n \"internal-only\",\n \"log-action\",\n data.eventName || data.errorName || \"UNKNOWN_CLI_EVENT\",\n (data.timestamp ? new Date(data.timestamp) : new Date()).toISOString(),\n JSON.stringify(data),\n ],\n cwd: connection.cwd,\n });\n });\n tracker.track(\"ClientConnection\", { extras: { cwd: connection.cwd } });\n\n // start listening to messages\n let api: ServerToClientAPI | null = new ServerToClientAPI(\n platform,\n connection,\n tracker,\n logger\n );\n api.setActiveRepoForCwd(connection.cwd);\n\n return () => {\n api?.dispose();\n api = null;\n };\n}\n","import type { PlatformName } from \"@withgraphite/gti-shared\";\nimport { CLOSED_AND_SHOULD_NOT_RECONNECT_CODE } from \"@withgraphite/gti-shared\";\nimport fs from \"fs\";\nimport http from \"http\";\nimport type { AddressInfo } from \"net\";\nimport path from \"path\";\nimport urlModule from \"url\";\nimport WebSocket from \"ws\";\n\nimport { onClientConnection } from \"../src/index\";\nimport { repositoryCache } from \"../src/RepositoryCache\";\nimport type { ServerPlatform } from \"../src/serverPlatform\";\nimport { areTokensEqual } from \"./proxyUtils\";\n\nexport type StartServerArgs = {\n port: number;\n sensitiveToken: string;\n challengeToken: string;\n logFileLocation: string;\n logInfo: (...args: Parameters<typeof console.log>) => void;\n command?: string;\n gtVersion: string;\n foreground: boolean;\n frontendDir: string;\n};\n\nexport type StartServerResult =\n | { type: \"addressInUse\" }\n | { type: \"success\"; port: number; pid: number }\n | { type: \"error\"; error: string };\n\nexport type ServerChallengeResponse = {\n challengeToken: string;\n /** Process ID for the server. */\n pid: number;\n};\n\nexport function startServer({\n port,\n sensitiveToken,\n challengeToken,\n logFileLocation,\n logInfo,\n command,\n gtVersion,\n foreground,\n frontendDir,\n}: StartServerArgs): Promise<StartServerResult> {\n return new Promise((resolve) => {\n try {\n const manifest = JSON.parse(\n fs.readFileSync(\n path.join(frontendDir, \"build/asset-manifest.json\"),\n \"utf-8\"\n )\n ) as { files: Array<string> };\n for (const file of Object.values(manifest.files)) {\n if (!file.startsWith(\"/\")) {\n resolve({\n type: \"error\",\n error: `expected entry to start with / but was: \\`${file}\\``,\n });\n }\n\n requestUrlToResource[file] = file.slice(1);\n }\n } catch (e) {\n // ignore...\n }\n\n // Anything not part of the asset-manifest we need to explicitly serve\n requestUrlToResource[`/favicon.ico`] = \"favicon.ico\";\n\n /**\n * Event listener for HTTP server \"error\" event.\n */\n function onError(error: { syscall?: string; code?: string }) {\n if (error.syscall !== \"listen\") {\n resolve({ type: \"error\", error: error.toString() });\n throw error;\n }\n\n // handle specific listen errors with friendly messages\n switch (error.code) {\n case \"EACCES\": {\n resolve({\n type: \"error\",\n error: `Port ${port} requires elevated privileges`,\n });\n throw error;\n }\n\n case \"EADDRINUSE\": {\n resolve({ type: \"addressInUse\" });\n return;\n }\n\n default:\n resolve({ type: \"error\", error: error.toString() });\n throw error;\n }\n }\n\n /**\n * Create HTTP server.\n */\n const server = http.createServer(async (req, res) => {\n if (req.url) {\n // Only the websocket is sensitive and requires the token.\n // Normal resource requests don't need to check the token.\n const { pathname } = urlModule.parse(req.url);\n // eslint-disable-next-line no-prototype-builtins\n if (pathname != null && requestUrlToResource.hasOwnProperty(pathname)) {\n const relativePath = requestUrlToResource[pathname];\n let contents: string | Buffer;\n try {\n contents = await fs.promises.readFile(\n path.join(frontendDir, \"build\", relativePath)\n );\n } catch (e: unknown) {\n res.writeHead(500, { \"Content-Type\": \"text/plain\" });\n res.end(htmlEscape((e as Error).toString()));\n return;\n }\n\n const lastDot = relativePath.lastIndexOf(\".\");\n const ext = relativePath.slice(lastDot + 1);\n const contentType = extensionToMIMEType[ext] ?? \"text/plain\";\n\n res.writeHead(200, { \"Content-Type\": contentType });\n res.end(contents);\n return;\n } else if (pathname === \"/challenge_authenticity\") {\n // requests to /challenge_authenticity?token=... allow using the sensistive token to ask\n // for the secondary challenge token.\n const requestToken = getSearchParams(req.url).get(\"token\");\n if (requestToken && areTokensEqual(requestToken, sensitiveToken)) {\n // they know the original token, we can tell them our challenge token\n res.writeHead(200, { \"Content-Type\": \"text/json\" });\n const response: ServerChallengeResponse = {\n challengeToken,\n pid: process.pid,\n };\n res.end(JSON.stringify(response));\n } else {\n res.writeHead(401, { \"Content-Type\": \"text/json\" });\n res.end(JSON.stringify({ error: \"invalid token\" }));\n }\n return;\n }\n }\n\n res.writeHead(404, { \"Content-Type\": \"text/html\" });\n res.end(\"<html><body>Not Found!</body></html>\");\n });\n\n /**\n * Listen on provided port, on all network interfaces.\n */\n const httpServer = server.listen(port);\n const wsServer = new WebSocket.Server({ noServer: true, path: \"/ws\" });\n wsServer.on(\"connection\", (socket, connectionRequest) => {\n // We require websocket connections to contain the token as a URL search parameter.\n let providedToken: string | undefined;\n let cwd: string | undefined;\n let platform: string | undefined;\n if (connectionRequest.url) {\n const searchParams = getSearchParams(connectionRequest.url);\n providedToken = searchParams.get(\"token\");\n const cwdParam = searchParams.get(\"cwd\");\n platform = searchParams.get(\"platform\") as string;\n if (cwdParam) {\n cwd = decodeURIComponent(cwdParam);\n }\n }\n if (!providedToken) {\n const reason = \"No token provided in websocket request\";\n logInfo(\"closing ws:\", reason);\n socket.close(CLOSED_AND_SHOULD_NOT_RECONNECT_CODE, reason);\n return;\n }\n if (!areTokensEqual(providedToken, sensitiveToken)) {\n const reason = \"Invalid token\";\n logInfo(\"closing ws:\", reason);\n socket.close(CLOSED_AND_SHOULD_NOT_RECONNECT_CODE, reason);\n return;\n }\n\n const platformImpl: ServerPlatform | undefined = undefined;\n switch (platform as PlatformName) {\n default:\n case undefined:\n break;\n }\n\n const dispose = onClientConnection({\n postMessage(message: string | ArrayBuffer) {\n socket.send(message);\n return Promise.resolve(true);\n },\n onDidReceiveMessage(handler) {\n const emitter = socket.on(\"message\", handler);\n const dispose = () => emitter.off(\"message\", handler);\n return { dispose };\n },\n cwd: cwd ?? process.cwd(),\n logFileLocation:\n logFileLocation === \"stdout\" ? undefined : logFileLocation,\n command,\n version: gtVersion,\n\n platform: platformImpl,\n });\n socket.on(\"close\", () => {\n dispose();\n\n // After disposing, we may not have anymore servers alive anymore.\n // We can proactively clean up the server so you get the latest version next time you try.\n // This way, we only re-use servers if you keep the tab open.\n // Note: since we trigger this cleanup on dispose, if you start a server with `--no-open`,\n // it won't clean itself up until you connect at least once.\n if (!foreground) {\n // We do this on a 1-minute delay in case you close a tab and quickly re-open it.\n setTimeout(() => {\n checkIfServerShouldCleanItselfUp();\n }, 60_000);\n }\n });\n });\n httpServer.on(\"upgrade\", (request, socket, head) => {\n wsServer.handleUpgrade(request, socket, head, (socket) => {\n wsServer.emit(\"connection\", socket, request);\n });\n });\n\n server.on(\"error\", onError);\n\n // return succesful result when the server is successfully listening\n server.on(\"listening\", () =>\n resolve({\n type: \"success\",\n port: (server.address() as AddressInfo).port,\n pid: process.pid,\n })\n );\n });\n}\n\nfunction checkIfServerShouldCleanItselfUp() {\n if (repositoryCache.numberOfActiveServers() === 0) {\n process.exit(0);\n }\n}\n\nfunction getSearchParams(url: string): Map<string, string> {\n const searchParamsArray = urlModule\n .parse(url)\n .search?.replace(/^\\?/, \"\")\n .split(\"&\")\n .map(\n (pair: string): [string, string] => pair.split(\"=\") as [string, string]\n );\n\n return new Map(searchParamsArray);\n}\n\nconst extensionToMIMEType: { [key: string]: string } = {\n css: \"text/css\",\n html: \"text/html\",\n js: \"text/javascript\",\n ttf: \"font/ttf\",\n};\n\nconst requestUrlToResource: { [key: string]: string } = {\n \"/\": \"index.html\",\n};\n\nfunction htmlEscape(str: string): string {\n return str\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\")\n .replace(/'/g, \"\");\n}\n"],"names":["ComparisonType","exports","comparison","type","UncommittedChanges","HeadChanges","StackChanges","Committed","hash","LRU","constructor","maxItems","maxHashCollision","Map","get","key","result","hashKey","getHashKey","valueMap","cache","undefined","maybeValue","k","v","delete","set","value","size","next","keys","done","clear","hashCodeFunc","hashCode","apply","cachedFunction","func","opts","_a","cacheSize","_b","getExtraKeys","cachedFunc","args","stats","every","isCachable","skip","cacheKey","cachedValue","hit","miss","_c","arg1","arg2","Object","values","filter","_target","_propertyKey","descriptor","originalFunc","cacheDecorator","cachableTypeNames","Set","arg","typeName","has","__exportStar","Tracker","sendData","context","error","eventName","errorName","data","errorMessage","Error","message","String","track","operation","startTime","Date","now","id","parentId","then","finalResult","duration","catch","err","Promise","reject","trackAsParent","trackData","childData","ctx","timestamp","AbortController","node_abort_controller_1","wait","leading","timeout","shouldCallLeading","debouncer","callback","clearTimeout","setTimeout","reset","isPending","SelfUpdate","inner","equals","other","otherInner","paths","options","pathObjects","map","path","separator","replace","length","guessSeparator","rootPrefixResult","exec","rootPrefix","depth","parts","split","reverse","part","hadLeadingSeparator","startsWith","maxDepth","Math","max","pathObject","pathObjectsToProcess","groupedPathObjects","currentDepth","slice","join","add","pathObjectGroup","Array","from","resultPathParts","alwaysShowLeadingSeparator","DiffType","DIFF","RENAME_FROM","RENAME_TO","COPY_FROM","COPY_TO","NEW_FILE_MODE","DELETED_FILE_MODE","OLD_MODE","NEW_MODE","HUNK_HEADER","OLD_FILE_HEADER","NEW_FILE_HEADER","DELIMITERS","assert","condition","msg","patch","diffstr","delimiters","match","list","i","parseIndex","index","hunks","push","line","header","oldFileName","newFileName","parseHeader","test","parseOldMode","parseNewMode","parseDeletedFileMode","parseNewFileMode","parseCopy","parseRename","parseFileHeader","parseHunk","parseHunks","arr","oldMode","Modified","newMode","Removed","Added","Copied","Renamed","hunkHeader","hunk","oldStart","oldLines","newStart","newLines","lines","linedelimiters","addCount","removeCount","indexOf","UNDEFINED_SERIALIZED","__rpcType","serialize","entries","val","stack","valueOf","isArray","a","newObj","propertyName","propertyValue","deserialize","specific","e","standardObject","JSON","stringify","parse","CommandRunner","revset","ErrorShortMessages","toString","random","deferred","promise","resolve","s","delimiter","foundIndex","lastIndexOf","start","className","el","classList","contains","parentElement","o","fromEntries","gen","iter1","iter2","iterator1","Symbol","iterator","iterator2","result1","result2","text","maxLength","substring","getUsername","username","osInfoError","env","process","unwrap","LOGNAME","USER","LNAME","USERNAME","processEnvError","ServerSideContext","logger","setRepo","repo","this","codeReviewProvider","getSummaryName","noOp","_data","stdoutLogger","console","TypedEventEmitter","EventEmitter","GitHubCodeReviewProvider","codeReviewSystem","runCommand","diffSummaries","onChangeDiffSummaries","handleData","handleError","on","dispose","off","async","_diffs","prs","stdout","emit","removeAllListeners","hostname","owner","runExternalCommand","_cwd","_args","_onProgress","_signal","_kind","_query","OperationQueue","runCallback","queuedOperations","runningOperation","abortController","onProgress","tracker","cwd","kind","queue","handleCommandProgress","op","exitCode","controller","newAbortController","trackEventName","extras","runner","_p","signal","shift","runOrQueueOperation","errString","log","abortRunningOperation","operationId","abort","PageFocusTracker","focusedPages","visiblePages","onChangeHandlers","setState","page","state","handler","disposePage","hasPageWithFocus","hasVisiblePage","onChange","RateLimiter","maxSimultaneousRunning","queued","running","runs","nextId","generateId","tryDequeueNext","includes","res","ran","notifyFinished","toRun","run","sleep","timeMs","serializeAsyncCall","asyncFun","scheduledCall","pendingCall","startAsyncCall","resultPromise","callNext","scheduleNextCall","Watchman","client","serializedReconnect","reconnectDelayMs","subscriptions","lastKnownClockTimes","status","watchmanBinaryPath","initWatchmanClient","tries","reconnectClient","warn","info","setStatus","localDirectoryPath","rawSubscriptionName","subscriptionOptions","subscriptionName","fixupName","existingSubscription","getSubscription","subscriptionCount","watch","watchRoot","relative_path","relativePath","watchProject","clock","fields","since","relative_root","empty_on_fresh_instance","subscription","root","pathFromSubscriptionRootToSubscriptionPath","name","emitter","setSubscription","subscribe","unsubscribe","deleteSubscription","statusBeforeError","end","onSubscriptionResult","bind","restoreSubscriptions","watchSubscriptions","numSubscriptions","numRestored","all","entryPath","response","is_fresh_instance","files","canceled","stateEnter","stateLeave","stateMessage","subscriptionPath","command","directoryPath","warning","DEFAULT_POLL_INTERVAL","ONE_MINUTE_MS","VISIBLE_POLL_INTERVAL","FOCUSED_POLL_INTERVAL","WatchForChanges","repoInfo","pageFocusTracker","changeCallback","static","watchman","disposables","setupWatchmanSubscriptions","setupPolling","poll","lastFetch","desiredNextTickTime","elapsedTickTime","repoRoot","dotdir","relativeDotdir","FILE_CHANGE_WATCHMAN_SUBSCRIPTION","DIRSTATE_WATCHMAN_SUBSCRIPTION","handleRepositoryStateChange","debounce","dirstateSubscription","watchDirectoryRecursive","expression","defer","WATCHMAN_DEFER","changes","handleUncommittedChanges","uncommittedChangesSubscription","unwatch","forEach","MIN_REQUIRED_CLI_VERSION","Repository","IGNORE_COMMIT_MESSAGE_LINES_REGEX","mergeConflicts","uncommittedChanges","smartlogCommits","mergeConflictsEmitter","uncommittedChangesEmitter","smartlogCommitsChangesEmitter","smartlogCommitsBeginFetchingEmitter","uncommittedChangesBeginFetchingEmitter","onDidDispose","operationQueue","watchForChanges","currentVisibleCommitRangeIndex","visibleCommitRanges","DEFAULT_DAYS_OF_COMMITS_TO_LOAD","remote","fetchUncommittedChanges","fetchSmartlogCommits","checkForMergeConflicts","Graphite","runOperation","CodeReviewProvider","normalizedArgs","normalizeOperationArgs","seenDiffs","subscribeToSmartlogCommitsChanges","fetched","commits","newDiffs","diffIds","commit","pr","number","diffId","triggerDiffSummariesFetch","getAllDiffIds","nextVisibleCommitRangeInDays","onChangeConflictState","wasAlreadyInConflicts","file","stat","code","fetchStartTimestamp","output","proc","previousConflicts","commandOutput","newConflictData","conflicts","newConflicts","fetchCompletedTimestamp","newConflictSet","conflict","computeNewConflicts","maxConflictsToLog","remainingConflicts","getMergeConflicts","repoVersion","findVersion","versionFound","versionRequired","profile","repoInfoRaw","preferredBranchEdit","createPrsAs","findRepoProfile","findRepoInfo","getConfig","dotDir","rootDir","trunkBranch","abortRunningOpeation","cwdRelativeArgs","stdin","getExecParams","input","execution","stderr","addEventListener","child","kill","forceKillAfterTimeout","handleAbortSignalOnProcess","setPageFocus","getUncommittedChanges","subscribeToUncommittedChanges","change","p","getSmartlogCommits","subscribeToSmartlogCommitsBeginFetching","onStart","subscribeToUncommittedChangesBeginFetching","commitInfos","parseCommitInfoOutput","trim","NoCommitsFetched","subscribeToHeadCommit","headCommit","find","isHead","onData","newHead","branch","catLimiter","cat","enqueueRun","catArgs","stripFinalNewline","notEmpty","configName","setConfig","level","configValue","command_","args_","options_","appUrl","platform","LANG","EDITOR","GRAPHITE_INTERACTIVE","argv","browserServerPlatform","platformName","handleMessageFromClient","spawn","detached","stdio","windowsHide","windowsVerbatimArguments","unref","RepositoryReferenceImpl","disposeFunc","disposed","internalReference","RefCounted","references","isDisposed","ref","getNumberOfReferences","repositoryCache","RepositoryType","reposByRoot","activeReposEmitter","lookup","dirGuess","endsWith","getOrCreate","cmd","found","getRepoInfo","newlyFound","internalRef","lookupRepoInfoAndReuseIfPossible","cachedRepositoryForPath","onChangeActiveRepos","cb","clearCache","numberOfActiveServers","numActive","ServerToClientAPI","connection","listenersByType","incomingListener","repoDisposables","activeRepoRef","queuedMessages","currentState","pageId","randomId","messageExpectingBinaryFollowup","onDidReceiveMessage","buf","isBinary","handleIncomingMessageWithPayload","deserializeFromString","hasBinaryPayload","expectsBinaryPayload","handleIncomingMessage","setRepoError","disposeRepoDisposables","processQueuedMessages","setCurrentRepo","postMessage","summaries","head","allCommits","ancestor","publicCommit","current","partOfTrunk","parents","findPublicAncestor","public","serializeToString","setActiveRepoForCwd","newCwd","repoOrError","disposable","sub","payload","filename","uploadFile","handleIncomingGeneralMessage","handleIncomingMessageWithRepo","notifyListeners","version","subscriptionID","postUncommittedChanges","d","postSmartlogCommits","postMergeConflicts","progress","filePath","absolutePath","pathMod","fullPath","sep","absolutePathForFileInRepo","rm","revsetArgsForComparison","diff","numLines","content","templates","contents","typeahead","query","rangeInDays","daysToFetch","listeners","handle","cacheDir","LOCALAPPDATA","XDG_CACHE_HOME","b","aBuf","Buffer","bBuf","timingSafeEqual","onClientConnection","logFileLocation","str","appendFile","getLogFileContents","readFile","fileLogger","writeToServer","sessionId","unixname","osArch","osType","osRelease","generateAnalyticsInfo","makeServerSideTracker","toISOString","api","startServer","port","sensitiveToken","challengeToken","logInfo","gtVersion","foreground","frontendDir","manifest","requestUrlToResource","server","req","url","pathname","hasOwnProperty","writeHead","lastDot","ext","contentType","extensionToMIMEType","requestToken","getSearchParams","pid","httpServer","listen","wsServer","noServer","socket","connectionRequest","providedToken","searchParams","cwdParam","decodeURIComponent","reason","close","CLOSED_AND_SHOULD_NOT_RECONNECT_CODE","send","exit","request","handleUpgrade","syscall","address","searchParamsArray","search","pair","css","html","js","ttf"],"sourceRoot":""}
|
|
1
|
+
{"version":3,"file":"325.js","mappings":"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","sources":["webpack://@withgraphite/graphite-cli/../../src/Comparison.ts","webpack://@withgraphite/graphite-cli/../../src/LRU.ts","webpack://@withgraphite/graphite-cli/../../../src/analytics/index.ts","webpack://@withgraphite/graphite-cli/../../../src/analytics/tracker.ts","webpack://@withgraphite/graphite-cli/../../src/compat.ts","webpack://@withgraphite/graphite-cli/../../src/debounce.ts","webpack://@withgraphite/graphite-cli/../../src/immutableExt.ts","webpack://@withgraphite/graphite-cli/../../src/index.ts","webpack://@withgraphite/graphite-cli/../../src/minimalDisambiguousPaths.ts","webpack://@withgraphite/graphite-cli/../../../src/patch/parse.ts","webpack://@withgraphite/graphite-cli/../../src/serialize.ts","webpack://@withgraphite/graphite-cli/../../../src/types/client.ts","webpack://@withgraphite/graphite-cli/../../../src/types/constants.ts","webpack://@withgraphite/graphite-cli/../../../src/types/index.ts","webpack://@withgraphite/graphite-cli/../../src/utils.ts","webpack://@withgraphite/graphite-cli/../gti-server/src/analytics/environment.ts","webpack://@withgraphite/graphite-cli/../gti-server/src/analytics/serverSideTracker.ts","webpack://@withgraphite/graphite-cli/../gti-server/src/logger.ts","webpack://@withgraphite/graphite-cli/../gti-server/src/TypedEventEmitter.ts","webpack://@withgraphite/graphite-cli/../gti-server/src/github/githubCodeReviewProvider.ts","webpack://@withgraphite/graphite-cli/../gti-server/src/OperationQueue.ts","webpack://@withgraphite/graphite-cli/../gti-server/src/PageFocusTracker.ts","webpack://@withgraphite/graphite-cli/../gti-server/src/RateLimiter.ts","webpack://@withgraphite/graphite-cli/../gti-server/src/utils.ts","webpack://@withgraphite/graphite-cli/../gti-server/src/watchman.ts","webpack://@withgraphite/graphite-cli/../gti-server/src/WatchForChanges.ts","webpack://@withgraphite/graphite-cli/../gti-server/src/Repository.ts","webpack://@withgraphite/graphite-cli/../gti-server/src/fs.ts","webpack://@withgraphite/graphite-cli/../gti-server/src/serverPlatform.ts","webpack://@withgraphite/graphite-cli/../gti-server/src/RepositoryCache.ts","webpack://@withgraphite/graphite-cli/../gti-server/src/ServerToClientAPI.ts","webpack://@withgraphite/graphite-cli/../gti-server/proxy/existingServerStateFiles.ts","webpack://@withgraphite/graphite-cli/../gti-server/proxy/proxyUtils.ts","webpack://@withgraphite/graphite-cli/../gti-server/src/index.ts","webpack://@withgraphite/graphite-cli/../gti-server/proxy/server.ts"],"sourcesContent":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,"import type { ApplicationInfo } from \"@withgraphite/gti-shared\";\nimport { randomId, unwrap } from \"@withgraphite/gti-shared\";\nimport os from \"os\";\n\nexport function getUsername(): string {\n try {\n return os.userInfo().username;\n } catch (osInfoError) {\n try {\n const { env } = process;\n return unwrap(env.LOGNAME || env.USER || env.LNAME || env.USERNAME);\n } catch (processEnvError) {\n throw new Error(String(processEnvError) + String(osInfoError));\n }\n }\n}\n\nexport function generateAnalyticsInfo(\n platformName: string,\n version: string\n): ApplicationInfo {\n return {\n platform: platformName,\n version,\n repo: undefined,\n /**\n * Random id for this GTI session, created at startup.\n * Note: this is only generated on the server, so client-logged events share the ID with the server.\n */\n sessionId: randomId(),\n unixname: getUsername(),\n osArch: os.arch(),\n osType: os.platform(),\n osRelease: os.release(),\n hostname: os.hostname(),\n };\n}\n","import type {\n ApplicationInfo,\n FullTrackData,\n Logger,\n TrackDataWithEventName,\n} from \"@withgraphite/gti-shared\";\nimport { Tracker } from \"@withgraphite/gti-shared\";\n\nimport type { Repository } from \"../Repository\";\nimport type { ServerPlatform } from \"../serverPlatform\";\nimport { generateAnalyticsInfo } from \"./environment\";\n\nexport type ServerSideTracker = Tracker<ServerSideContext>;\n\nclass ServerSideContext {\n constructor(public logger: Logger, public data: ApplicationInfo) {}\n\n public setRepo(repo: Repository | undefined): void {\n this.data.repo = repo?.codeReviewProvider?.getSummaryName();\n }\n}\n\nconst noOp = (_data: FullTrackData): Promise<unknown> | void => {\n /* In open source builds, analytics tracking is completely disabled/removed. */\n};\n\n/**\n * Creates a Tracker which includes server-side-only cached application data like platform, username, etc,\n * and sends data to the underlying analytics engine outside of GTI.\n * This can not be global since two client connections may have different cached data.\n */\nexport function makeServerSideTracker(\n logger: Logger,\n platform: ServerPlatform,\n version: string,\n // prettier-ignore\n writeToServer = noOp\n): ServerSideTracker {\n return new Tracker(\n (data: TrackDataWithEventName, context: ServerSideContext) => {\n const { logger } = context;\n // log track event, since tracking events can be used as datapoints when reviewing logs\n logger.log(\n \"[track]\",\n data.eventName,\n data.errorName ?? \"\",\n data.errorMessage ?? \"\",\n data.extras != null ? JSON.stringify(data.extras) : \"\"\n );\n try {\n Promise.resolve(writeToServer({ ...data, ...context.data })).catch(\n (err) => void err\n );\n } catch {\n // pass\n }\n },\n new ServerSideContext(\n logger,\n generateAnalyticsInfo(platform.platformName, version)\n )\n );\n}\n","import type { Logger } from \"@withgraphite/gti-shared\";\nimport fs from \"fs\";\nimport util from \"util\";\n\nexport const stdoutLogger = console;\n\nexport function fileLogger(filename: string): Logger {\n const log = (...args: Parameters<typeof console.log>) => {\n const str = util.format(...args) + \"\\n\";\n void fs.promises.appendFile(filename, str);\n };\n\n return {\n info: log,\n log,\n warn: log,\n error: log,\n\n getLogFileContents: () => {\n return fs.promises.readFile(filename, \"utf-8\");\n },\n };\n}\n","import { EventEmitter } from \"events\";\n\n/**\n * Like {@link EventEmitter}, but with type checking for one particular subscription type,\n * plus errors.\n * ```\n * const myEmitter = new TypedEventEmitter<'data', number>();\n * myEmitter.on('data', (data: number) => ...); // typechecks 'data' param and callback\n * myEmitter.on('error', (error: Error) => ...); // errors are always allowed too\n * // Fields other than 'data' and 'error' are type errors.\n * ```\n */\nexport declare interface TypedEventEmitter<\n EventName extends string,\n EventType\n> {\n on(event: EventName, listener: (data: EventType) => void): this;\n on(event: \"error\", listener: (error: Error) => void): this;\n off(event: EventName, listener: (data: EventType) => void): this;\n off(event: \"error\", listener: (error: Error) => void): this;\n\n emit(\n ...args: EventType extends undefined\n ? [event: EventName] | [event: EventName, data: EventType]\n : [event: EventName, data: EventType]\n ): boolean;\n emit(event: \"error\", error: Error): boolean;\n}\n\nexport class TypedEventEmitter<\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n EventName extends string,\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n EventType\n> extends EventEmitter {}\n","import type { PRInfo, PRNumber } from \"@withgraphite/gti-cli-shared-types\";\nimport type {\n CodeReviewSystem,\n Disposable,\n GitHubDiffSummary,\n OperationCommandProgressReporter,\n Result,\n TypeaheadKind,\n TypeaheadResult,\n} from \"@withgraphite/gti-shared\";\nimport type execa from \"execa\";\n\nimport { TypedEventEmitter } from \"../TypedEventEmitter\";\n\ntype GitHubCodeReviewSystem = CodeReviewSystem & { type: \"github\" };\nexport class GitHubCodeReviewProvider {\n constructor(\n private codeReviewSystem: GitHubCodeReviewSystem,\n private runCommand: (\n args: Array<string>,\n cwd?: string,\n options?: execa.Options\n ) => execa.ExecaChildProcess<string>\n ) {}\n private diffSummaries = new TypedEventEmitter<\"data\", GitHubDiffSummary[]>();\n\n onChangeDiffSummaries(\n callback: (result: Result<GitHubDiffSummary[]>) => unknown\n ): Disposable {\n const handleData = (data: GitHubDiffSummary[]) => callback({ value: data });\n const handleError = (error: Error) => callback({ error });\n this.diffSummaries.on(\"data\", handleData);\n this.diffSummaries.on(\"error\", handleError);\n return {\n dispose: () => {\n this.diffSummaries.off(\"data\", handleData);\n this.diffSummaries.off(\"error\", handleError);\n },\n };\n }\n\n public async triggerDiffSummariesFetch(_diffs: Array<PRNumber>) {\n const value = await this.runCommand([\"internal-only\", \"prs\"]);\n const prs = JSON.parse(value.stdout) as PRInfo[];\n this.diffSummaries.emit(\"data\", prs);\n }\n\n public dispose() {\n this.diffSummaries.removeAllListeners();\n }\n\n public getSummaryName(): string {\n return `github:${this.codeReviewSystem.hostname}/${this.codeReviewSystem.owner}/${this.codeReviewSystem.repo}`;\n }\n\n /** Run a command not handled within graphite, such as a separate submit handler */\n public runExternalCommand(\n _cwd: string,\n _args: Array<string>,\n _onProgress: OperationCommandProgressReporter,\n _signal: AbortSignal\n ): Promise<void> {\n throw new Error(\n \"GitHub code review provider does not support running external commands\"\n );\n }\n\n public async typeahead(\n _kind: TypeaheadKind,\n _query: string\n ): Promise<Array<TypeaheadResult>> {\n return Promise.resolve([]);\n }\n}\n\n// function githubCheckSuitesToCIStatus(\n// checkSuites: CheckSuiteConnection | undefined | null,\n// ): DiffSignalSummary {\n// let anyInProgress = false;\n// let anyWarning = false;\n// for (const checkSuite of checkSuites?.nodes ?? []) {\n// switch (checkSuite?.status) {\n// case CheckStatusState.Completed:\n// {\n// switch (checkSuite?.conclusion) {\n// case CheckConclusionState.Success:\n// break;\n// case CheckConclusionState.Neutral:\n// case CheckConclusionState.Stale:\n// case CheckConclusionState.Skipped:\n// anyWarning = true;\n// break;\n// case CheckConclusionState.ActionRequired:\n// case CheckConclusionState.StartupFailure:\n// case CheckConclusionState.Cancelled:\n// case CheckConclusionState.TimedOut:\n// case CheckConclusionState.Failure:\n// return 'failed'; // no need to look at other signals\n// }\n// }\n// break;\n// case CheckStatusState.Waiting:\n// case CheckStatusState.Requested:\n// case CheckStatusState.Queued:\n// case CheckStatusState.Pending:\n// case CheckStatusState.InProgress:\n// anyInProgress = true;\n// break;\n// }\n// }\n// return anyWarning ? 'warning' : anyInProgress ? 'running' : 'pass';\n// }\n","import type {\n Logger,\n OperationCommandProgressReporter,\n OperationProgress,\n RunnableOperation,\n} from \"@withgraphite/gti-shared\";\nimport { newAbortController } from \"@withgraphite/gti-shared\";\n\nimport type { ServerSideTracker } from \"./analytics/serverSideTracker\";\n\n/**\n * Handle running & queueing all Operations so that only one Operation runs at once.\n * Operations may be run by gt in the Repository or other providers like ghstack in the RemoteRepository.\n */\nexport class OperationQueue {\n constructor(\n private logger: Logger,\n private runCallback: (\n operation: RunnableOperation,\n cwd: string,\n handleProgress: OperationCommandProgressReporter,\n signal: AbortSignal\n ) => Promise<void>\n ) {}\n\n private queuedOperations: Array<\n RunnableOperation & { tracker: ServerSideTracker }\n > = [];\n private runningOperation: RunnableOperation | undefined = undefined;\n private abortController: AbortController | undefined = undefined;\n\n async runOrQueueOperation(\n operation: RunnableOperation,\n onProgress: (progress: OperationProgress) => void,\n tracker: ServerSideTracker,\n cwd: string\n ): Promise<void> {\n if (this.runningOperation != null) {\n this.queuedOperations.push({ ...operation, tracker });\n onProgress({\n id: operation.id,\n kind: \"queue\",\n queue: this.queuedOperations.map((o) => o.id),\n });\n return;\n }\n this.runningOperation = operation;\n\n const handleCommandProgress: OperationCommandProgressReporter = (\n ...args\n ) => {\n switch (args[0]) {\n case \"spawn\":\n onProgress({\n id: operation.id,\n kind: \"spawn\",\n queue: this.queuedOperations.map((op) => op.id),\n });\n break;\n\n case \"stdout\":\n onProgress({ id: operation.id, kind: \"stdout\", message: args[1] });\n break;\n\n case \"stderr\":\n onProgress({ id: operation.id, kind: \"stderr\", message: args[1] });\n break;\n\n case \"exit\":\n onProgress({\n id: operation.id,\n kind: \"exit\",\n exitCode: args[1],\n timestamp: Date.now(),\n });\n break;\n }\n };\n\n try {\n const controller = newAbortController();\n this.abortController = controller;\n await tracker.operation(\n operation.trackEventName,\n \"RunOperationError\",\n { extras: { args: operation.args, runner: operation.runner } },\n (_p) =>\n this.runCallback(\n operation,\n cwd,\n handleCommandProgress,\n controller.signal\n )\n );\n this.runningOperation = undefined;\n\n // now that we successfully ran this operation, dequeue the next\n if (this.queuedOperations.length > 0) {\n const op = this.queuedOperations.shift();\n if (op != null) {\n // don't await this, the caller should resolve when the original operation finishes.\n void this.runOrQueueOperation(\n op,\n // TODO: we're using the onProgress from the LAST `runOperation`... should we be keeping the newer onProgress in the queued operation?\n onProgress,\n op.tracker,\n cwd\n );\n }\n }\n } catch (err) {\n const errString = (err as Error).toString();\n this.logger.log(\n \"error running operation: \",\n operation.args[0],\n errString\n );\n onProgress({ id: operation.id, kind: \"error\", error: errString });\n // clear queue to run when we hit an error\n this.queuedOperations = [];\n this.runningOperation = undefined;\n }\n }\n\n /**\n * Send kill signal to the running operation if the operationId matches.\n * If the process exits, the exit event will be noticed by the queue.\n * This function does not block on waiting for the operation process to exit.\n */\n abortRunningOperation(operationId: string) {\n if (this.runningOperation?.id == operationId) {\n this.abortController?.abort();\n }\n }\n}\n","import type { PageVisibility } from \"@withgraphite/gti-shared\";\n\n/**\n * Aggregates if any GTI page has focus or visibility.\n */\nexport class PageFocusTracker {\n private focusedPages = new Set();\n private visiblePages = new Set();\n\n private onChangeHandlers = new Set<(state: PageVisibility) => unknown>();\n\n setState(page: string, state: PageVisibility) {\n switch (state) {\n case \"focused\":\n this.focusedPages.add(page);\n this.visiblePages.add(page);\n break;\n\n case \"visible\":\n this.focusedPages.delete(page);\n this.visiblePages.add(page);\n break;\n\n case \"hidden\":\n this.focusedPages.delete(page);\n this.visiblePages.delete(page);\n break;\n }\n for (const handler of this.onChangeHandlers) {\n handler(state);\n }\n }\n\n public disposePage(page: string) {\n this.focusedPages.delete(page);\n this.visiblePages.delete(page);\n }\n\n public hasPageWithFocus() {\n return this.focusedPages.size > 0;\n }\n public hasVisiblePage() {\n return this.visiblePages.size > 0;\n }\n\n public onChange(callback: () => unknown): () => void {\n this.onChangeHandlers.add(callback);\n return () => this.onChangeHandlers.delete(callback);\n }\n}\n","import { TypedEventEmitter } from \"./TypedEventEmitter\";\n\ntype Id = number;\n\n/**\n * Rate limits requests to run an arbitrary task.\n * Up to `maxSimultaneousRunning` tasks can run at once,\n * futher requests will be queued and run when a running task finishes.\n *\n * Usage:\n * ```\n * const rateLimiter = new RateLimiter(5);\n * const result = await rateLimiter.enqueueRun(() => {\n * // ...do arbitrary async work...\n * });\n * ```\n */\nexport class RateLimiter {\n private queued: Array<Id> = [];\n private running: Array<Id> = [];\n private runs = new TypedEventEmitter<\"run\", Id>();\n\n constructor(\n private maxSimultaneousRunning: number,\n private log?: (s: string) => unknown\n ) {}\n\n private nextId = 1;\n private generateId(): Id {\n return this.nextId++;\n }\n\n async enqueueRun<T>(runner: () => Promise<T>): Promise<T> {\n const id = this.generateId();\n\n this.queued.push(id);\n this.tryDequeueNext();\n\n if (!this.running.includes(id)) {\n this.log?.(\n `${this.running.length} tasks are already running, enqueuing ID:${id}`\n );\n await new Promise((res) => {\n this.runs.on(\"run\", (ran) => {\n if (ran === id) {\n this.log?.(`now allowing ID:${id} to run`);\n res(undefined);\n }\n });\n });\n }\n\n try {\n return await runner();\n } finally {\n this.notifyFinished(id);\n }\n }\n\n private notifyFinished(id: Id): void {\n this.running = this.running.filter((running) => running !== id);\n this.tryDequeueNext();\n }\n\n private tryDequeueNext() {\n if (this.running.length < this.maxSimultaneousRunning) {\n const toRun = this.queued.shift();\n if (toRun != null) {\n this.run(toRun);\n }\n }\n }\n\n private run(id: Id) {\n this.running.push(id);\n this.runs.emit(\"run\", id);\n }\n}\n","import type { BranchInfo } from \"@withgraphite/gti-cli-shared-types\";\nimport type { SmartlogCommits } from \"@withgraphite/gti-shared\";\nimport { truncate } from \"@withgraphite/gti-shared\";\nimport type { ExecaChildProcess } from \"execa\";\nimport type execa from \"execa\";\nimport os from \"os\";\n\nexport function sleep(timeMs: number): Promise<void> {\n return new Promise((res) => setTimeout(res, timeMs));\n}\n\nexport function firstOfIterable<T>(\n iterable: IterableIterator<T>\n): T | undefined {\n return iterable.next().value;\n}\n\n/**\n * Limits async function execution parallelism to only one at a time.\n * Hence, if a call is already running, it will wait for it to finish,\n * then start the next async execution, but if called again while not finished,\n * it will return the scheduled execution promise.\n *\n * Sample Usage:\n * ```\n * let i = 1;\n * const oneExecAtATime = serializeAsyncCall(() => {\n * return new Promise((resolve, reject) => {\n * setTimeout(200, () => resolve(i++));\n * });\n * });\n *\n * const result1Promise = oneExecAtATime(); // Start an async, and resolve to 1 in 200 ms.\n * const result2Promise = oneExecAtATime(); // Schedule the next async, and resolve to 2 in 400 ms.\n * const result3Promise = oneExecAtATime(); // Reuse scheduled promise and resolve to 2 in 400 ms.\n * ```\n */\nexport function serializeAsyncCall<T>(\n asyncFun: () => Promise<T>\n): () => Promise<T> {\n let scheduledCall: Promise<T> | undefined = undefined;\n let pendingCall: Promise<undefined> | undefined = undefined;\n const startAsyncCall = () => {\n const resultPromise = asyncFun();\n pendingCall = resultPromise.then(\n () => (pendingCall = undefined),\n () => (pendingCall = undefined)\n );\n return resultPromise;\n };\n const callNext = () => {\n scheduledCall = undefined;\n return startAsyncCall();\n };\n const scheduleNextCall = () => {\n if (scheduledCall == null) {\n if (pendingCall == null) {\n throw new Error(\"pendingCall must not be null!\");\n }\n scheduledCall = pendingCall.then(callNext, callNext);\n }\n return scheduledCall;\n };\n return () => {\n if (pendingCall == null) {\n return startAsyncCall();\n } else {\n return scheduleNextCall();\n }\n };\n}\n\n/**\n * Kill `child` on `AbortSignal`.\n *\n * This is slightly more robust than execa 6.0 and nodejs' `signal` support:\n * if a process was stopped (by `SIGTSTP` or `SIGSTOP`), it can still be killed.\n */\nexport function handleAbortSignalOnProcess(\n child: ExecaChildProcess,\n signal: AbortSignal\n) {\n signal.addEventListener(\"abort\", () => {\n if (os.platform() == \"win32\") {\n // Signals are ignored on Windows.\n // execa's default forceKillAfterTimeout behavior does not\n // make sense for Windows. Disable it explicitly.\n child.kill(\"SIGKILL\", { forceKillAfterTimeout: false });\n } else {\n // If the process is stopped (ex. Ctrl+Z, kill -STOP), make it\n // continue first so it can respond to signals including SIGKILL.\n child.kill(\"SIGCONT\");\n // A good citizen process should exit soon after recieving SIGTERM.\n // In case it doesn't, send SIGKILL after 5 seconds.\n child.kill(\"SIGTERM\", { forceKillAfterTimeout: 5000 });\n }\n });\n}\n\n/**\n * Given a list of commits and a starting commit,\n * traverse up the chain of `parents` until we find a public commit\n */\nexport function findPublicAncestor(\n allCommits: SmartlogCommits | undefined,\n from: BranchInfo\n): BranchInfo | undefined {\n let publicCommit: BranchInfo | undefined;\n if (allCommits != null) {\n const map = new Map(allCommits.map((commit) => [commit.branch, commit]));\n\n let current: BranchInfo | undefined = from;\n while (current != null) {\n if (current.partOfTrunk) {\n publicCommit = current;\n break;\n }\n if (current.parents[0] == null) {\n break;\n }\n current = map.get(current.parents[0]);\n }\n }\n\n return publicCommit;\n}\n\n/**\n * Run a command that is expected to produce JSON output.\n * Return a JSON object. On error, the JSON object has property \"error\".\n */\nexport function parseExecJson<T>(\n exec: execa.ExecaChildProcess,\n reply: (parsed?: T, error?: string) => void\n) {\n exec\n .then((result) => {\n const stdout = result.stdout;\n try {\n const parsed = JSON.parse(stdout);\n if (parsed.error != null) {\n reply(undefined, parsed.error);\n } else {\n reply(parsed as T);\n }\n } catch (err) {\n const msg = `Cannot parse ${truncate(\n result.escapedCommand\n )} output. (error: ${err}, stdout: ${stdout})`;\n reply(undefined, msg);\n }\n })\n .catch((err) => {\n // Try extracting error from stdout '{error: message}'.\n try {\n const parsed = JSON.parse(err.stdout);\n if (parsed.error != null) {\n reply(undefined, parsed.error);\n return;\n }\n } catch {\n // pass\n }\n // Fallback to general error.\n const msg = `Cannot run ${truncate(err.escapedCommand)}. (error: ${err})`;\n reply(undefined, msg);\n });\n}\n","import type { Logger } from \"@withgraphite/gti-shared\";\nimport { EventEmitter } from \"events\";\nimport watchman from \"fb-watchman\";\nimport path from \"path\";\n\nimport { firstOfIterable, serializeAsyncCall, sleep } from \"./utils\";\n\nexport type WatchmanSubscriptionOptions = {\n fields?: Array<string>;\n expression?: Array<unknown>;\n since?: string;\n defer?: Array<string>;\n defer_vcs?: boolean;\n relative_root?: string;\n empty_on_fresh_instance?: boolean;\n};\n\nexport type WatchmanSubscription = {\n root: string;\n /**\n * The relative path from subscriptionRoot to subscriptionPath.\n * This is the 'relative_path' as described at\n * https://facebook.github.io/watchman/docs/cmd/watch-project.html#using-watch-project.\n * Notably, this value should be undefined if subscriptionRoot is the same as\n * subscriptionPath.\n */\n pathFromSubscriptionRootToSubscriptionPath: string | undefined;\n path: string;\n name: string;\n subscriptionCount: number;\n options: WatchmanSubscriptionOptions;\n emitter: EventEmitter;\n};\n\nexport type WatchmanSubscriptionResponse = {\n root: string;\n subscription: string;\n files?: Array<FileChange>;\n \"state-enter\"?: string;\n \"state-leave\"?: string;\n canceled?: boolean;\n clock?: string;\n is_fresh_instance?: boolean;\n};\n\nexport type FileChange = {\n name: string;\n new: boolean;\n exists: boolean;\n};\n\nconst WATCHMAN_SETTLE_TIME_MS = 2500;\nconst DEFAULT_WATCHMAN_RECONNECT_DELAY_MS = 100;\nconst MAXIMUM_WATCHMAN_RECONNECT_DELAY_MS = 60 * 1000;\n\nexport class Watchman {\n private client: watchman.Client;\n\n private serializedReconnect: () => Promise<void>;\n private reconnectDelayMs: number = DEFAULT_WATCHMAN_RECONNECT_DELAY_MS;\n private subscriptions: Map<string, WatchmanSubscription> = new Map();\n private lastKnownClockTimes: Map<string, string> = new Map();\n\n public readonly status:\n | \"initializing\"\n | \"reconnecting\"\n | \"healthy\"\n | \"ended\"\n | \"errored\" = \"initializing\";\n\n constructor(private logger: Logger) {\n this.client = new watchman.Client({\n // find watchman using PATH\n watchmanBinaryPath: undefined,\n });\n this.initWatchmanClient();\n this.serializedReconnect = serializeAsyncCall(async () => {\n let tries = 0;\n // eslint-disable-next-line no-constant-condition\n while (true) {\n try {\n // eslint-disable-next-line no-await-in-loop\n await this.reconnectClient();\n return;\n } catch (error) {\n this.logger.warn(\n `reconnectClient failed (try #${tries}):`,\n error instanceof Error ? error.message : error\n );\n tries++;\n\n this.reconnectDelayMs *= 2; // exponential backoff\n if (this.reconnectDelayMs > MAXIMUM_WATCHMAN_RECONNECT_DELAY_MS) {\n this.reconnectDelayMs = MAXIMUM_WATCHMAN_RECONNECT_DELAY_MS;\n }\n\n this.logger.info(\n \"Calling reconnectClient from _serializedReconnect in %dms\",\n this.reconnectDelayMs\n );\n // eslint-disable-next-line no-await-in-loop\n await sleep(this.reconnectDelayMs);\n }\n }\n });\n }\n\n setStatus(status: typeof this.status): void {\n this.logger.log(\"Watchman status: \", status);\n (this.status as string) = status;\n }\n\n public async watchDirectoryRecursive(\n localDirectoryPath: string,\n rawSubscriptionName: string,\n subscriptionOptions?: WatchmanSubscriptionOptions\n ): Promise<WatchmanSubscription> {\n // Subscriptions should be unique by name and by folder\n const subscriptionName = this.fixupName(\n localDirectoryPath,\n rawSubscriptionName\n );\n const existingSubscription = this.getSubscription(subscriptionName);\n if (existingSubscription) {\n existingSubscription.subscriptionCount++;\n\n return existingSubscription;\n } else {\n const { watch: watchRoot, relative_path: relativePath } =\n await this.watchProject(localDirectoryPath);\n const clock = await this.clock(watchRoot);\n const options: WatchmanSubscriptionOptions = {\n ...subscriptionOptions,\n // Do not add `mode` here, it is very unfriendly to watches on Eden (see https://fburl.com/0z023yy0)\n fields:\n subscriptionOptions != null && subscriptionOptions.fields != null\n ? subscriptionOptions.fields\n : [\"name\", \"new\", \"exists\"],\n since: clock,\n };\n if (relativePath) {\n options.relative_root = relativePath;\n }\n // Try this thing out where we always set empty_on_fresh_instance. Eden will be a lot happier\n // if we never ask Watchman to do something that results in a glob(**) near the root.\n options.empty_on_fresh_instance = true;\n\n // relativePath is undefined if watchRoot is the same as directoryPath.\n const subscription: WatchmanSubscription = {\n root: watchRoot,\n pathFromSubscriptionRootToSubscriptionPath: relativePath,\n path: localDirectoryPath,\n name: subscriptionName,\n subscriptionCount: 1,\n options,\n emitter: new EventEmitter(),\n };\n this.setSubscription(subscriptionName, subscription);\n await this.subscribe(watchRoot, subscriptionName, options);\n this.logger.log(\"watchman subscription %s established\", subscriptionName);\n this.setStatus(\"healthy\");\n\n return subscription;\n }\n }\n\n public async unwatch(path: string, name: string): Promise<void> {\n const subscriptionName = this.fixupName(path, name);\n const subscription = this.getSubscription(subscriptionName);\n\n if (subscription == null) {\n this.logger.error(\n `No watcher entity found with path [${path}] name [${name}]`\n );\n return;\n }\n\n if (--subscription.subscriptionCount === 0) {\n await this.unsubscribe(subscription.path, subscription.name);\n this.deleteSubscription(subscriptionName);\n this.logger.log(\"watchman subscription %s destroyed\", subscriptionName);\n }\n }\n\n private initWatchmanClient(): void {\n this.client.on(\"end\", () => {\n this.setStatus(\"ended\");\n this.logger.info(\"Watchman client ended\");\n this.client.removeAllListeners();\n void this.serializedReconnect();\n });\n this.client.on(\"error\", (error: Error) => {\n const statusBeforeError = this.status;\n this.logger.error(\"Error while talking to watchman: \", error);\n this.setStatus(\"errored\");\n // If Watchman encounters an error in the middle of a command, it may never finish!\n // The client must be immediately killed here so that the command fails and\n // `serializeAsyncCall` can be unblocked. Otherwise, we end up in a deadlock.\n this.client.removeAllListeners();\n this.client.end();\n if (statusBeforeError === \"initializing\") {\n // If we get an error while we're first initializing watchman, it probably means\n // it's not installed properly. No use spamming reconnection failures too.\n return;\n }\n // Those are errors in deserializing a stream of changes.\n // The only possible recovery here is reconnecting a new client,\n // but the failed to serialize events will be missed.\n void this.serializedReconnect();\n });\n this.client.on(\"subscription\", this.onSubscriptionResult.bind(this));\n }\n\n private async reconnectClient(): Promise<void> {\n // If we got an error after making a subscription, the reconnect needs to\n // remove that subscription to try again, so it doesn't keep leaking subscriptions.\n this.logger.info(\"Ending existing watchman client to reconnect a new one\");\n this.setStatus(\"reconnecting\");\n this.client.removeAllListeners();\n this.client.end();\n this.client = new watchman.Client({\n // find watchman using PATH\n watchmanBinaryPath: undefined,\n });\n this.logger.error(\n \"Watchman client disconnected, reconnecting a new client!\"\n );\n this.initWatchmanClient();\n this.logger.info(\"Watchman client re-initialized, restoring subscriptions\");\n await this.restoreSubscriptions();\n }\n\n private async restoreSubscriptions(): Promise<void> {\n const watchSubscriptions = Array.from(this.subscriptions.values());\n const numSubscriptions = watchSubscriptions.length;\n this.logger.info(\n `Attempting to restore ${numSubscriptions} Watchman subscriptions.`\n );\n let numRestored = 0;\n await Promise.all(\n watchSubscriptions.map(\n async (subscription: WatchmanSubscription, index: number) => {\n // Note that this call to `watchman watch-project` could fail if the\n // subscription.path has been unmounted/deleted.\n await this.watchProject(subscription.path);\n\n // We have already missed the change events from the disconnect time,\n // watchman could have died, so the last clock result is not valid.\n await sleep(WATCHMAN_SETTLE_TIME_MS);\n\n // Register the subscriptions after the filesystem settles.\n const { name, options, root } = subscription;\n\n // Assuming we had previously connected and gotten an event, we can\n // reconnect `since` that time, so that we get any events we missed.\n subscription.options.since =\n this.lastKnownClockTimes.get(root) || (await this.clock(root));\n\n this.logger.info(\n `Subscribing to ${name}: (${index + 1}/${numSubscriptions})`\n );\n await this.subscribe(root, name, options);\n ++numRestored;\n this.logger.info(\n `Subscribed to ${name}: (${numRestored}/${numSubscriptions}) complete.`\n );\n }\n )\n );\n if (numRestored > 0 && numRestored === numSubscriptions) {\n this.logger.info(\n \"Successfully reconnected all %d subscriptions.\",\n numRestored\n );\n // if everything got restored, reset the reconnect backoff time\n this.reconnectDelayMs = DEFAULT_WATCHMAN_RECONNECT_DELAY_MS;\n this.setStatus(\"healthy\");\n }\n }\n\n private getSubscription(entryPath: string): WatchmanSubscription | undefined {\n return this.subscriptions.get(path.normalize(entryPath));\n }\n\n private setSubscription(\n entryPath: string,\n subscription: WatchmanSubscription\n ): void {\n const key = path.normalize(entryPath);\n this.subscriptions.set(key, subscription);\n }\n\n private deleteSubscription(entryPath: string): void {\n const key = path.normalize(entryPath);\n this.subscriptions.delete(key);\n }\n\n private onSubscriptionResult(response: WatchmanSubscriptionResponse): void {\n const subscription = this.getSubscription(response.subscription);\n if (subscription == null) {\n this.logger.error(\"Subscription not found for response:!\", response);\n return;\n }\n\n // save the clock time of this event in case we disconnect in the future\n if (response != null && response.root != null && response.clock != null) {\n this.lastKnownClockTimes.set(response.root, response.clock);\n }\n if (response.is_fresh_instance === true) {\n this.logger.warn(\n `Watch for ${response.root} (${response.subscription}) returned an empty fresh instance.`\n );\n subscription.emitter.emit(\"fresh-instance\");\n } else if (Array.isArray(response.files)) {\n subscription.emitter.emit(\"change\", response.files);\n } else if (response.canceled === true) {\n this.logger.info(\n `Watch for ${response.root} was deleted: triggering a reconnect.`\n );\n // Ending the client will trigger a reconnect.\n this.client.end();\n } else {\n // Only log state transisions once per watchmanClient, since otherwise we'll just get 8x of this message spammed\n if (firstOfIterable(this.subscriptions.values()) === subscription) {\n // TODO(most): use state messages to decide on when to send updates.\n const stateEnter = response[\"state-enter\"];\n const stateLeave = response[\"state-leave\"];\n const stateMessage =\n stateEnter != null\n ? `Entering ${stateEnter}`\n : `Leaving ${stateLeave}`;\n const numSubscriptions = this.subscriptions.size;\n this.logger.info(\n `Subscription state: ${stateMessage} (${numSubscriptions})`\n );\n }\n }\n }\n\n private fixupName(path: string, name: string): string {\n const refinedPath = path.replace(/\\\\/g, \"-\").replace(/\\//g, \"-\");\n return `${refinedPath}-${name}`;\n }\n\n private unsubscribe(\n subscriptionPath: string,\n subscriptionName: string\n ): Promise<unknown> {\n return this.command(\"unsubscribe\", subscriptionPath, subscriptionName);\n }\n\n private async watchProject(\n directoryPath: string\n ): Promise<{ watch: string; relative_path: string }> {\n const response = (await this.command(\"watch-project\", directoryPath)) as {\n watch: string;\n relative_path: string;\n warning?: string;\n };\n if (response.warning) {\n this.logger.error(\"watchman warning: \", response.warning);\n }\n return response;\n }\n\n private async clock(directoryPath: string): Promise<string> {\n const { clock } = (await this.command(\"clock\", directoryPath)) as {\n clock: string;\n };\n return clock;\n }\n\n private subscribe(\n watchRoot: string,\n subscriptionName: string | undefined,\n options: WatchmanSubscriptionOptions\n ): Promise<WatchmanSubscription> {\n this.logger.info(\n `Creating Watchman subscription ${String(\n subscriptionName\n )} under ${watchRoot}`,\n JSON.stringify(options)\n );\n return this.command(\n \"subscribe\",\n watchRoot,\n subscriptionName,\n options\n ) as Promise<WatchmanSubscription>;\n }\n\n /**\n * Promisify calls to watchman client.\n */\n private async command(...args: Array<unknown>): Promise<unknown> {\n try {\n return await new Promise((resolve, reject) => {\n this.client.command(args, (error, response) =>\n error ? reject(error) : resolve(response)\n );\n });\n } catch (error) {\n this.logger.error(\"Watchman command error: \", args, error);\n throw error;\n }\n }\n}\n","import type {\n Logger,\n PageVisibility,\n RepoInfo,\n} from \"@withgraphite/gti-shared\";\nimport { debounce, ONE_MINUTE_MS } from \"@withgraphite/gti-shared\";\nimport path from \"path\";\n\nimport type { PageFocusTracker } from \"./PageFocusTracker\";\nimport { Watchman } from \"./watchman\";\n\nconst DEFAULT_POLL_INTERVAL = 5 * ONE_MINUTE_MS;\nconst VISIBLE_POLL_INTERVAL = 1 * ONE_MINUTE_MS;\nconst FOCUSED_POLL_INTERVAL = 0.25 * ONE_MINUTE_MS;\nconst ON_FOCUS_REFETCH_THROTTLE = 10_000;\nconst ON_VISIBLE_REFETCH_THROTTLE = 20_000;\n\nexport type KindOfChange =\n | \"uncommitted changes\"\n | \"branches\"\n | \"merge conflicts\"\n | \"everything\";\n\n/**\n * Handles watching for changes to files on disk which should trigger refetching data,\n * and polling for changes when watching is not reliable.\n */\nexport class WatchForChanges {\n static WATCHMAN_DEFER = `hg.update`; // TODO: update to sl\n public watchman: Watchman;\n\n private disposables: Array<() => unknown> = [];\n\n // eslint-disable-next-line max-params\n constructor(\n private repoInfo: RepoInfo,\n private logger: Logger,\n private pageFocusTracker: PageFocusTracker,\n private changeCallback: (kind: KindOfChange) => unknown,\n watchman?: Watchman | undefined\n ) {\n this.watchman = watchman ?? new Watchman(logger);\n\n void this.setupWatchmanSubscriptions();\n this.setupPolling();\n this.pageFocusTracker.onChange(this.poll.bind(this));\n }\n\n private timeout: NodeJS.Timeout | undefined;\n private lastFetch = new Date().valueOf();\n\n /**\n * Combine different signals to determine what interval to poll for information\n */\n private setupPolling() {\n this.timeout = setTimeout(this.poll, DEFAULT_POLL_INTERVAL);\n }\n\n /**\n * Re-trigger fetching data from the repository,\n * depending on how recently that data was last fetched,\n * and whether any GTI windows are focused or visible.\n *\n * This function calls itself on an interval to check whether we should fetch changes,\n * but it can also be called in response to events like focus being gained.\n */\n public poll = (kind?: PageVisibility | \"force\") => {\n // calculate how long we'd like to be waiting from what we know of the windows.\n let desiredNextTickTime = DEFAULT_POLL_INTERVAL;\n if (this.watchman.status !== \"healthy\") {\n if (this.pageFocusTracker.hasPageWithFocus()) {\n desiredNextTickTime = FOCUSED_POLL_INTERVAL;\n } else if (this.pageFocusTracker.hasVisiblePage()) {\n desiredNextTickTime = VISIBLE_POLL_INTERVAL;\n }\n }\n\n const now = Date.now();\n const elapsedTickTime = now - this.lastFetch;\n\n if (\n kind === \"force\" ||\n // we've been waiting longer than desired\n elapsedTickTime >= desiredNextTickTime ||\n // the moment a window gains focus or visibility, consider polling immediately\n (kind === \"focused\" && elapsedTickTime >= ON_FOCUS_REFETCH_THROTTLE) ||\n (kind === \"visible\" && elapsedTickTime >= ON_VISIBLE_REFETCH_THROTTLE)\n ) {\n // it's time to fetch\n this.changeCallback(\"everything\");\n this.lastFetch = Date.now();\n\n clearTimeout(this.timeout);\n this.timeout = setTimeout(this.poll, desiredNextTickTime);\n } else {\n // we have some time left before we we would expect to need to poll, schedule next poll\n clearTimeout(this.timeout);\n this.timeout = setTimeout(\n this.poll,\n desiredNextTickTime - elapsedTickTime\n );\n }\n };\n\n private async setupWatchmanSubscriptions() {\n if (this.repoInfo.type !== \"success\") {\n return;\n }\n const { repoRoot, dotdir } = this.repoInfo;\n\n if (repoRoot == null || dotdir == null) {\n this.logger.error(\n `skipping watchman subscription since ${repoRoot} is not a repository`\n );\n return;\n }\n const relativeDotdir = path.relative(repoRoot, dotdir);\n\n const FILE_CHANGE_WATCHMAN_SUBSCRIPTION = \"graphite-smartlog-file-change\";\n const DIRSTATE_WATCHMAN_SUBSCRIPTION = \"graphite-smartlog-dirstate-change\";\n try {\n const handleRepositoryStateChange = debounce(() => {\n // if the repo changes, also recheck files. E.g. if you commit, your uncommitted changes will also change.\n this.changeCallback(\"everything\");\n\n // reset timer for polling\n this.lastFetch = new Date().valueOf();\n }, 100); // debounce so that multiple quick changes don't trigger multiple fetches for no reason\n const dirstateSubscription = await this.watchman.watchDirectoryRecursive(\n repoRoot,\n DIRSTATE_WATCHMAN_SUBSCRIPTION,\n {\n fields: [\"name\"],\n expression: [\n \"name\",\n [\n `${relativeDotdir}/refs/heads`,\n `${relativeDotdir}/refs/branch-metadata`,\n `${relativeDotdir}/rebase-merge`,\n `${relativeDotdir}/index`,\n `${relativeDotdir}/HEAD`,\n ],\n \"wholename\",\n ],\n defer: [WatchForChanges.WATCHMAN_DEFER],\n empty_on_fresh_instance: true,\n }\n );\n dirstateSubscription.emitter.on(\"change\", (changes) => {\n if (changes.includes(`${relativeDotdir}/rebase-merge`)) {\n this.changeCallback(\"merge conflicts\");\n }\n if (changes.includes(`${relativeDotdir}/index`)) {\n this.changeCallback(\"uncommitted changes\");\n }\n if (\n changes.includes(`${relativeDotdir}/refs/heads`) ||\n changes.includes(`${relativeDotdir}/refs/branch-metadata`) ||\n changes.includes(`${relativeDotdir}/HEAD`)\n ) {\n this.changeCallback(\"branches\");\n }\n });\n dirstateSubscription.emitter.on(\n \"fresh-instance\",\n handleRepositoryStateChange\n );\n\n const handleUncommittedChanges = () => {\n this.changeCallback(\"uncommitted changes\");\n\n // reset timer for polling\n this.lastFetch = new Date().valueOf();\n };\n const uncommittedChangesSubscription =\n await this.watchman.watchDirectoryRecursive(\n repoRoot,\n FILE_CHANGE_WATCHMAN_SUBSCRIPTION,\n {\n // We only need to know that a change happened (not the list of files) so that we can trigger `status`\n fields: [\"name\"],\n expression: [\n \"allof\",\n // This watchman subscription is used to determine when and which\n // files to fetch new statuses for. There is no reason to include\n // directories in these updates, and in fact they may make us overfetch\n // statuses.\n // This line restricts this subscription to only return files.\n [\"type\", \"f\"],\n [\"not\", [\"dirname\", relativeDotdir]],\n // Even though we tell it not to match .git, modifying a file inside .git\n // will emit an event for the folder itself, which we want to ignore.\n [\"not\", [\"match\", relativeDotdir, \"basename\"]],\n ],\n defer: [WatchForChanges.WATCHMAN_DEFER],\n empty_on_fresh_instance: true,\n }\n );\n uncommittedChangesSubscription.emitter.on(\n \"change\",\n handleUncommittedChanges\n );\n uncommittedChangesSubscription.emitter.on(\n \"fresh-instance\",\n handleUncommittedChanges\n );\n\n this.disposables.push(() => {\n void this.watchman.unwatch(repoRoot, DIRSTATE_WATCHMAN_SUBSCRIPTION);\n void this.watchman.unwatch(repoRoot, FILE_CHANGE_WATCHMAN_SUBSCRIPTION);\n });\n } catch (err) {\n this.logger.error(\"failed to setup watchman subscriptions\", err);\n }\n }\n\n public dispose() {\n this.disposables.forEach((dispose) => dispose());\n if (this.timeout) {\n clearTimeout(this.timeout);\n this.timeout = undefined;\n }\n }\n}\n","import type {\n BranchInfo,\n PRNumber,\n RepoInfo as RepoInfoFromCLI,\n RepoRelativePath,\n Status,\n} from \"@withgraphite/gti-cli-shared-types\";\nimport type {\n AbsolutePath,\n CodeReviewSystem,\n CommandArg,\n Disposable,\n FetchedCommits,\n FetchedUncommittedChanges,\n Logger,\n MergeConflicts,\n OperationCommandProgressReporter,\n OperationProgress,\n PageVisibility,\n RepoInfo,\n RunnableOperation,\n SmartlogCommits,\n SuccessorInfo,\n ValidatedRepoInfo,\n} from \"@withgraphite/gti-shared\";\nimport {\n CommandRunner,\n Comparison,\n ComparisonType,\n DEFAULT_DAYS_OF_COMMITS_TO_LOAD,\n ErrorShortMessages,\n notEmpty,\n unwrap,\n} from \"@withgraphite/gti-shared\";\nimport execa from \"execa\";\nimport path from \"path\";\nimport semver from \"semver\";\n\nimport type { ServerSideTracker } from \"./analytics/serverSideTracker\";\nimport { exists, removeLeadingPathSep } from \"./fs\";\nimport { GitHubCodeReviewProvider } from \"./github/githubCodeReviewProvider\";\nimport { OperationQueue } from \"./OperationQueue\";\nimport { PageFocusTracker } from \"./PageFocusTracker\";\nimport { RateLimiter } from \"./RateLimiter\";\nimport { TypedEventEmitter } from \"./TypedEventEmitter\";\nimport { handleAbortSignalOnProcess, serializeAsyncCall } from \"./utils\";\nimport { WatchForChanges } from \"./WatchForChanges\";\n\nexport const COMMIT_END_MARK = \"<<COMMIT_END_MARK>>\";\nexport const NULL_CHAR = \"\\0\";\nconst MAX_SIMULTANEOUS_CAT_CALLS = 4;\n\nconst MIN_REQUIRED_CLI_VERSION = \"0.1.4\";\n\ntype ConflictFileData = {\n contents: string;\n exists: boolean;\n isexec: boolean;\n issymlink: boolean;\n};\nexport type ResolveCommandConflictOutput = [\n | {\n command: null;\n conflicts: [];\n pathconflicts: [];\n }\n | {\n command: string;\n command_details: { cmd: string; to_abort: string; to_continue: string };\n conflicts: Array<{\n base: ConflictFileData;\n local: ConflictFileData;\n output: ConflictFileData;\n other: ConflictFileData;\n path: string;\n }>;\n pathconflicts: Array<never>;\n }\n];\n\n/**\n * This class is responsible for providing information about the working copy\n * for a Graphite repository.\n *\n * A Repository may be reused by multiple connections, not just one GTI window.\n * This is so we don't duplicate watchman subscriptions and calls to status/log.\n * A Repository does not have a pre-defined `cwd`, so it may be re-used across cwds.\n *\n * Prefer using `RepositoryCache.getOrCreate()` to access and dispose `Repository`s.\n */\nexport class Repository {\n public IGNORE_COMMIT_MESSAGE_LINES_REGEX = /^((?:HG|SL):.*)/gm;\n\n private mergeConflicts: MergeConflicts | undefined = undefined;\n private uncommittedChanges: FetchedUncommittedChanges | null = null;\n private smartlogCommits: FetchedCommits | null = null;\n\n private mergeConflictsEmitter = new TypedEventEmitter<\n \"change\",\n MergeConflicts | undefined\n >();\n private uncommittedChangesEmitter = new TypedEventEmitter<\n \"change\",\n FetchedUncommittedChanges\n >();\n private smartlogCommitsChangesEmitter = new TypedEventEmitter<\n \"change\",\n FetchedCommits\n >();\n\n private smartlogCommitsBeginFetchingEmitter = new TypedEventEmitter<\n \"start\",\n undefined\n >();\n private uncommittedChangesBeginFetchingEmitter = new TypedEventEmitter<\n \"start\",\n undefined\n >();\n\n private disposables: Array<() => void> = [\n () => this.mergeConflictsEmitter.removeAllListeners(),\n () => this.uncommittedChangesEmitter.removeAllListeners(),\n () => this.smartlogCommitsChangesEmitter.removeAllListeners(),\n () => this.smartlogCommitsBeginFetchingEmitter.removeAllListeners(),\n () => this.uncommittedChangesBeginFetchingEmitter.removeAllListeners(),\n ];\n public onDidDispose(callback: () => unknown): void {\n this.disposables.push(callback);\n }\n\n private operationQueue: OperationQueue;\n private watchForChanges: WatchForChanges;\n private pageFocusTracker = new PageFocusTracker();\n public codeReviewProvider?: GitHubCodeReviewProvider;\n\n private currentVisibleCommitRangeIndex = 0;\n private visibleCommitRanges: Array<number | undefined> = [\n DEFAULT_DAYS_OF_COMMITS_TO_LOAD,\n 60,\n undefined,\n ];\n\n /** Prefer using `RepositoryCache.getOrCreate()` to access and dispose `Repository`s. */\n constructor(public info: ValidatedRepoInfo, public logger: Logger) {\n const remote = info.codeReviewSystem;\n if (remote.type === \"github\") {\n this.codeReviewProvider = new GitHubCodeReviewProvider(\n remote,\n this.runCommand.bind(this)\n );\n }\n\n this.watchForChanges = new WatchForChanges(\n info,\n logger,\n this.pageFocusTracker,\n (kind) => {\n if (kind === \"uncommitted changes\") {\n void this.fetchUncommittedChanges();\n } else if (kind === \"branches\") {\n void this.fetchSmartlogCommits();\n } else if (kind === \"merge conflicts\") {\n void this.checkForMergeConflicts();\n } else if (kind === \"everything\") {\n void this.fetchUncommittedChanges();\n void this.fetchSmartlogCommits();\n void this.checkForMergeConflicts();\n }\n }\n );\n\n this.operationQueue = new OperationQueue(\n this.logger,\n (\n operation: RunnableOperation,\n cwd: string,\n handleCommandProgress,\n signal: AbortSignal\n ): Promise<void> => {\n if (operation.runner === CommandRunner.Graphite) {\n return this.runOperation(\n operation,\n handleCommandProgress,\n cwd,\n signal\n );\n } else if (operation.runner === CommandRunner.CodeReviewProvider) {\n const normalizedArgs = this.normalizeOperationArgs(\n cwd,\n operation.args\n );\n\n if (this.codeReviewProvider?.runExternalCommand == null) {\n return Promise.reject(\n Error(\n \"CodeReviewProvider does not support running external commands\"\n )\n );\n }\n\n return (\n this.codeReviewProvider?.runExternalCommand(\n cwd,\n normalizedArgs,\n handleCommandProgress,\n signal\n ) ?? Promise.resolve()\n );\n }\n return Promise.resolve();\n }\n );\n\n // refetch summaries whenever we see new diffIds\n const seenDiffs = new Set();\n const subscription = this.subscribeToSmartlogCommitsChanges((fetched) => {\n if (fetched.commits.value) {\n const newDiffs = [];\n const diffIds = fetched.commits.value\n .filter((commit) => commit.pr)\n .map((commit) => commit.pr?.number);\n for (const diffId of diffIds) {\n if (!seenDiffs.has(diffId)) {\n newDiffs.push(diffId);\n seenDiffs.add(diffId);\n }\n }\n if (newDiffs.length > 0) {\n void this.codeReviewProvider?.triggerDiffSummariesFetch(\n // We could choose to only fetch the diffs that changed (`newDiffs`) rather than all diffs,\n // but our UI doesn't cache old values, thus all other diffs would appear empty\n this.getAllDiffIds()\n );\n }\n }\n });\n\n // the repo may already be in a conflict state on startup\n void this.checkForMergeConflicts();\n\n this.disposables.push(() => subscription.dispose());\n }\n\n public nextVisibleCommitRangeInDays(): number | undefined {\n if (\n this.currentVisibleCommitRangeIndex + 1 <\n this.visibleCommitRanges.length\n ) {\n this.currentVisibleCommitRangeIndex++;\n }\n return this.visibleCommitRanges[this.currentVisibleCommitRangeIndex];\n }\n\n /**\n * Typically, disposing is handled by `RepositoryCache` and not used directly.\n */\n public dispose() {\n this.disposables.forEach((dispose) => dispose());\n this.codeReviewProvider?.dispose();\n this.watchForChanges.dispose();\n }\n\n public onChangeConflictState(\n callback: (conflicts: MergeConflicts | undefined) => unknown\n ): Disposable {\n this.mergeConflictsEmitter.on(\"change\", callback);\n\n if (this.mergeConflicts) {\n // if we're already in merge conflicts, let the client know right away\n callback(this.mergeConflicts);\n }\n\n return {\n dispose: () => this.mergeConflictsEmitter.off(\"change\", callback),\n };\n }\n\n public checkForMergeConflicts = serializeAsyncCall(async () => {\n this.logger.info(\"checking for merge conflicts\");\n // Fast path: check if .git/merge dir changed\n const wasAlreadyInConflicts = this.mergeConflicts != null;\n if (!wasAlreadyInConflicts) {\n const mergeDirExists = await exists(\n path.join(this.info.dotdir, \"rebase-merge\")\n );\n if (!mergeDirExists) {\n // Not in a conflict\n this.logger.info(\n `conflict state still the same (${\n wasAlreadyInConflicts ? \"IN merge conflict\" : \"NOT in conflict\"\n })`\n );\n return;\n }\n }\n\n if (this.mergeConflicts == null) {\n // notify UI that merge conflicts were detected and full details are loading\n this.mergeConflicts = { state: \"loading\" };\n this.mergeConflictsEmitter.emit(\"change\", this.mergeConflicts);\n }\n\n // More expensive full check for conflicts. Necessary if we see .gt/merge change, or if\n // we're already in a conflict and need to re-check if a conflict was resolved.\n\n const fetchStartTimestamp = Date.now();\n let output: Status;\n try {\n const proc = await this.runCommand([\"internal-only\", \"status\"]);\n output = JSON.parse(proc.stdout) as Status;\n } catch (err) {\n this.logger.error(`failed to check for merge conflicts: ${err}`);\n // To avoid being stuck in \"loading\" state forever, let's pretend there's no conflicts.\n this.mergeConflicts = undefined;\n this.mergeConflictsEmitter.emit(\"change\", this.mergeConflicts);\n return;\n }\n\n this.mergeConflicts = computeNewConflicts(\n this.mergeConflicts,\n output,\n fetchStartTimestamp\n );\n this.logger.info(\n `repo ${this.mergeConflicts ? \"IS\" : \"IS NOT\"} in merge conflicts`\n );\n if (this.mergeConflicts) {\n const maxConflictsToLog = 20;\n const remainingConflicts = (this.mergeConflicts.files ?? [])\n .filter((conflict) => conflict.status === \"UNRESOLVED\")\n .map((conflict) => conflict.path)\n .slice(0, maxConflictsToLog);\n this.logger.info(\"remaining files with conflicts: \", remainingConflicts);\n }\n this.mergeConflictsEmitter.emit(\"change\", this.mergeConflicts);\n });\n\n public getMergeConflicts(): MergeConflicts | undefined {\n return this.mergeConflicts;\n }\n\n /**\n * Determine basic repo info including the root and important config values.\n * Resulting RepoInfo may have null fields if cwd is not a valid repo root.\n * Throws if `command` is not found.\n */\n static async getRepoInfo(\n command: string | undefined,\n logger: Logger,\n cwd: string\n ): Promise<RepoInfo> {\n const repoVersion = await findVersion(command, logger, cwd).catch(\n (err: Error) => err\n );\n if (repoVersion instanceof Error) {\n return { type: \"invalidCommand\", command: command ?? \"gt\" };\n }\n if (\n repoVersion !== \"local\" &&\n repoVersion !== \"dev\" &&\n semver.lt(repoVersion, MIN_REQUIRED_CLI_VERSION)\n ) {\n return {\n type: \"invalidVersion\",\n command: command ?? \"gt\",\n versionFound: repoVersion,\n versionRequired: MIN_REQUIRED_CLI_VERSION,\n };\n }\n\n const [profile, repoInfoRaw, preferredBranchEdit, createPrsAs] =\n await Promise.all([\n findRepoProfile(command, logger, cwd),\n findRepoInfo(command, logger, cwd),\n getConfig(command, logger, cwd, \"graphite.branch_edit\").then(\n (value) => (value as \"commit\" | \"amend\") ?? (\"amend\" as const)\n ),\n getConfig(command, logger, cwd, \"graphite.create_prs_as\").then(\n (value) => (value as \"draft\" | \"publish\") ?? (\"draft\" as const)\n ),\n ]);\n if (repoInfoRaw == null) {\n return { type: \"cwdNotARepository\", cwd };\n }\n\n let codeReviewSystem: CodeReviewSystem;\n if (typeof repoInfoRaw.remote === \"undefined\") {\n codeReviewSystem = { type: \"none\" };\n } else {\n const { owner, name, hostname } = repoInfoRaw.remote;\n codeReviewSystem = {\n type: \"github\",\n owner,\n repo: name,\n hostname,\n };\n }\n\n const result: RepoInfo = {\n type: \"success\",\n command,\n dotdir: repoInfoRaw.dotDir,\n repoRoot: repoInfoRaw.rootDir,\n codeReviewSystem,\n preferredBranchEdit,\n createPrsAs,\n profile,\n trunkBranch: repoInfoRaw.trunkBranch,\n };\n logger.info(\"repo info: \", result);\n return result;\n }\n\n /**\n * Run long-lived command which mutates the repository state.\n * Progress is streamed back as it comes in.\n * Operations are run immediately. For queueing, see OperationQueue.\n */\n async runOrQueueOperation(\n operation: RunnableOperation,\n onProgress: (progress: OperationProgress) => void,\n tracker: ServerSideTracker,\n cwd: string\n ): Promise<void> {\n await this.operationQueue.runOrQueueOperation(\n operation,\n onProgress,\n tracker,\n cwd\n );\n\n // After any operation finishes, make sure we poll right away,\n // so the UI is guarnateed to get the latest data.\n this.watchForChanges.poll(\"force\");\n }\n\n /**\n * Abort the running operation if it matches the given id.\n */\n abortRunningOpeation(operationId: string) {\n this.operationQueue.abortRunningOperation(operationId);\n }\n\n /**\n * Called by this.operationQueue in response to runOrQueueOperation when an operation is ready to actually run.\n */\n private normalizeOperationArgs(\n cwd: string,\n args: Array<CommandArg>\n ): Array<string> {\n const repoRoot = unwrap(this.info.repoRoot);\n\n return args.map((arg) => {\n if (typeof arg === \"object\") {\n switch (arg.type) {\n case \"repo-relative-file\":\n return path.normalize(\n path.relative(cwd, path.join(repoRoot, arg.path))\n );\n\n case \"succeedable-revset\":\n return `max(successors(${arg.revset}))`;\n }\n }\n return arg;\n });\n }\n\n /**\n * Called by this.operationQueue in response to runOrQueueOperation when an operation is ready to actually run.\n */\n private async runOperation(\n operation: {\n id: string;\n args: Array<CommandArg>;\n stdin?: string;\n },\n onProgress: OperationCommandProgressReporter,\n cwd: string,\n signal: AbortSignal\n ): Promise<void> {\n const cwdRelativeArgs = this.normalizeOperationArgs(cwd, operation.args);\n const { stdin } = operation;\n const { command, args, options } = getExecParams(\n this.info.command,\n cwdRelativeArgs,\n cwd,\n stdin ? { input: stdin } : undefined\n );\n\n this.logger.log(\"run operation: \", command, cwdRelativeArgs.join(\" \"));\n\n const execution = execa(command, args, {\n ...options,\n stdout: \"pipe\",\n stderr: \"pipe\",\n });\n // It would be more appropriate to call this in reponse to execution.on('spawn'), but\n // this seems to be inconsistent about firing in all versions of node.\n // Just send spawn immediately. Errors during spawn like ENOENT will still be reported by `exit`.\n onProgress(\"spawn\");\n execution.stdout?.on(\"data\", (data) => {\n onProgress(\"stdout\", data.toString());\n });\n execution.stderr?.on(\"data\", (data) => {\n onProgress(\"stderr\", data.toString());\n });\n void execution.on(\"exit\", (exitCode) => {\n onProgress(\"exit\", exitCode || 0);\n });\n signal.addEventListener(\"abort\", () => {\n this.logger.log(\"kill operation: \", command, cwdRelativeArgs.join(\" \"));\n });\n handleAbortSignalOnProcess(execution, signal);\n await execution;\n }\n\n setPageFocus(page: string, state: PageVisibility) {\n this.pageFocusTracker.setState(page, state);\n }\n\n /** Return the latest fetched value for UncommittedChanges. */\n getUncommittedChanges(): FetchedUncommittedChanges | null {\n return this.uncommittedChanges;\n }\n\n subscribeToUncommittedChanges(\n callback: (result: FetchedUncommittedChanges) => unknown\n ): Disposable {\n this.uncommittedChangesEmitter.on(\"change\", callback);\n return {\n dispose: () => {\n this.uncommittedChangesEmitter.off(\"change\", callback);\n },\n };\n }\n\n fetchUncommittedChanges = serializeAsyncCall(async () => {\n const fetchStartTimestamp = Date.now();\n try {\n this.uncommittedChangesBeginFetchingEmitter.emit(\"start\");\n const proc = await this.runCommand([\"internal-only\", \"status\"]);\n const files = (JSON.parse(proc.stdout) as Status).files.map((change) => ({\n ...change,\n path: removeLeadingPathSep(change.path),\n }));\n\n this.uncommittedChanges = {\n fetchStartTimestamp,\n fetchCompletedTimestamp: Date.now(),\n files: { value: files },\n };\n this.uncommittedChangesEmitter.emit(\"change\", this.uncommittedChanges);\n } catch (err) {\n this.logger.error(\"Error fetching files: \", err);\n if (isProcessError(err)) {\n if (err.stderr.includes(\"checkout is currently in progress\")) {\n this.logger.info(\n \"Ignoring `hg status` error caused by in-progress checkout\"\n );\n return;\n }\n }\n // emit an error, but don't save it to this.uncommittedChanges\n this.uncommittedChangesEmitter.emit(\"change\", {\n fetchStartTimestamp,\n fetchCompletedTimestamp: Date.now(),\n files: { error: err instanceof Error ? err : new Error(err as string) },\n });\n }\n });\n\n /** Return the latest fetched value for SmartlogCommits. */\n getSmartlogCommits(): FetchedCommits | null {\n return this.smartlogCommits;\n }\n\n subscribeToSmartlogCommitsChanges(\n callback: (result: FetchedCommits) => unknown\n ) {\n this.smartlogCommitsChangesEmitter.on(\"change\", callback);\n return {\n dispose: () => {\n this.smartlogCommitsChangesEmitter.off(\"change\", callback);\n },\n };\n }\n\n subscribeToSmartlogCommitsBeginFetching(\n callback: (isFetching: boolean) => unknown\n ) {\n const onStart = () => callback(true);\n this.smartlogCommitsBeginFetchingEmitter.on(\"start\", onStart);\n return {\n dispose: () => {\n this.smartlogCommitsBeginFetchingEmitter.off(\"start\", onStart);\n },\n };\n }\n\n subscribeToUncommittedChangesBeginFetching(\n callback: (isFetching: boolean) => unknown\n ) {\n const onStart = () => callback(true);\n this.uncommittedChangesBeginFetchingEmitter.on(\"start\", onStart);\n return {\n dispose: () => {\n this.uncommittedChangesBeginFetchingEmitter.off(\"start\", onStart);\n },\n };\n }\n\n fetchSmartlogCommits = serializeAsyncCall(async () => {\n const fetchStartTimestamp = Date.now();\n try {\n this.smartlogCommitsBeginFetchingEmitter.emit(\"start\");\n const proc = await this.runCommand([\"internal-only\", \"log\"]);\n const commits = parseCommitInfoOutput(this.logger, proc.stdout.trim());\n if (commits.length === 0) {\n throw new Error(ErrorShortMessages.NoCommitsFetched);\n }\n this.smartlogCommits = {\n fetchStartTimestamp,\n fetchCompletedTimestamp: Date.now(),\n commits: { value: commits },\n };\n this.smartlogCommitsChangesEmitter.emit(\"change\", this.smartlogCommits);\n } catch (err) {\n this.logger.error(\"Error fetching commits: \", err);\n this.smartlogCommitsChangesEmitter.emit(\"change\", {\n fetchStartTimestamp,\n fetchCompletedTimestamp: Date.now(),\n commits: {\n error: err instanceof Error ? err : new Error(err as string),\n },\n });\n }\n });\n\n /** Watch for changes to the head commit, e.g. from checking out a new commit */\n subscribeToHeadCommit(callback: (head: BranchInfo) => unknown) {\n let headCommit = this.smartlogCommits?.commits.value?.find(\n (commit) => commit.isHead\n );\n if (headCommit != null) {\n callback(headCommit);\n }\n const onData = (data: FetchedCommits) => {\n const newHead = data?.commits.value?.find((commit) => commit.isHead);\n if (newHead != null && newHead.branch !== headCommit?.branch) {\n callback(newHead);\n headCommit = newHead;\n }\n };\n this.smartlogCommitsChangesEmitter.on(\"change\", onData);\n return {\n dispose: () => {\n this.smartlogCommitsChangesEmitter.off(\"change\", onData);\n },\n };\n }\n\n private catLimiter = new RateLimiter(MAX_SIMULTANEOUS_CAT_CALLS, (s) =>\n this.logger.info(\"[cat]\", s)\n );\n /** Return file content at a given revset, e.g. hash or `.` */\n public cat(file: AbsolutePath, comparison: Comparison): Promise<string> {\n const relativePath = path.relative(this.info.repoRoot, file);\n\n return this.catLimiter.enqueueRun(async () => {\n // For `gt cat`, we want the output of the command verbatim.\n const options = { stripFinalNewline: false };\n return (\n await this.runCommand(\n [\n \"internal-only\",\n \"relative-cat\",\n ...this.catArgs(comparison, relativePath),\n ],\n /*cwd=*/ undefined,\n options\n )\n ).stdout;\n });\n }\n\n private catArgs(comparison: Comparison, file: string): Array<string> {\n switch (comparison.type) {\n case ComparisonType.UncommittedChanges:\n return [\"uncommitted\", file];\n\n case ComparisonType.HeadChanges:\n return [\"head\", file];\n\n case ComparisonType.StackChanges:\n return [\"stack\", file];\n\n case ComparisonType.Committed:\n return [\"stack\", file, \"--ref\", comparison.hash];\n }\n }\n\n public getAllDiffIds(): Array<PRNumber> {\n return (\n this.getSmartlogCommits()\n ?.commits.value?.map((commit) => commit.pr?.number)\n .filter(notEmpty) ?? []\n );\n }\n\n public runCommand(\n args: Array<string>,\n cwd?: string,\n options?: execa.Options\n ): execa.ExecaChildProcess<string> {\n return runCommand({\n command: this.info.command,\n args,\n logger: this.logger,\n cwd: unwrap(cwd ?? this.info.repoRoot),\n options,\n });\n }\n\n public getConfig(configName: string): Promise<string | undefined> {\n return getConfig(\n this.info.command,\n this.logger,\n this.info.repoRoot,\n configName\n );\n }\n public setConfig(\n level: ConfigLevel,\n configName: string,\n configValue: string\n ): Promise<void> {\n return setConfig({\n command: this.info.command,\n logger: this.logger,\n cwd: this.info.repoRoot,\n level,\n configName,\n configValue,\n });\n }\n}\n\nexport function runCommand({\n command: command_,\n args: args_,\n logger,\n cwd,\n options: options_,\n}: {\n command?: string;\n args: Array<string>;\n logger?: Logger;\n cwd: string;\n options?: execa.Options;\n}): execa.ExecaChildProcess {\n const { command, args, options } = getExecParams(\n command_,\n args_,\n cwd,\n options_\n );\n if (logger) {\n logger.log(\"run command: \", command, ...args, options);\n }\n\n return execa(command, args, options);\n}\n\nasync function findVersion(\n command: string | undefined,\n logger: Logger,\n cwd: string\n): Promise<string> {\n try {\n return (\n await runCommand({\n command,\n args: [\"--version\"],\n logger,\n cwd,\n })\n ).stdout;\n } catch (error) {\n logger.error(`Failed to find gt version in ${cwd}`, error);\n throw error;\n }\n}\n\nasync function findRepoInfo(\n command: string | undefined,\n logger: Logger,\n cwd: string\n): Promise<RepoInfoFromCLI | undefined> {\n try {\n return JSON.parse(\n (\n await runCommand({\n command,\n args: [\"internal-only\", \"repo-info\"],\n logger,\n cwd,\n })\n ).stdout\n );\n } catch (error) {\n logger.error(`Failed to find repository info in ${cwd}`, error);\n return undefined;\n }\n}\n\nasync function findRepoProfile(\n command: string | undefined,\n logger: Logger,\n cwd: string\n): Promise<{\n appUrl: string;\n}> {\n try {\n return JSON.parse(\n (\n await runCommand({\n command,\n args: [\"internal-only\", \"profile\"],\n logger,\n cwd,\n })\n ).stdout\n );\n } catch (error) {\n logger.error(`Failed to find repository profile in ${cwd}`, error);\n return {\n appUrl: \"https://app.graphite.dev/\",\n };\n }\n}\n\nasync function getConfig(\n command: string | undefined,\n logger: Logger,\n cwd: string,\n configName: string\n): Promise<string | undefined> {\n try {\n return (\n await runCommand({\n command,\n args: [\"internal-only\", \"config\", configName],\n logger,\n cwd,\n })\n ).stdout.trim();\n } catch {\n // `config` exits with status 1 if config is not set. This is not an error.\n return undefined;\n }\n}\n\n// Eventually add repo\ntype ConfigLevel = \"user\";\nasync function setConfig({\n command,\n logger,\n cwd,\n level,\n configName,\n configValue,\n}: {\n command?: string;\n logger: Logger;\n cwd: string;\n level: ConfigLevel;\n configName: string;\n configValue: string;\n}): Promise<void> {\n await runCommand({\n command,\n args: [\n \"internal-only\",\n \"set-config\",\n `--level`,\n level,\n configName,\n configValue,\n ],\n logger,\n cwd,\n });\n}\n\nfunction getExecParams(\n command: string | undefined,\n args_: Array<string>,\n cwd: string,\n options_?: execa.Options\n): {\n command: string;\n args: Array<string>;\n options: execa.Options;\n} {\n let args = [...args_];\n // expandHomeDir is not supported on windows\n if (process.platform !== \"win32\") {\n // commit/amend have unconventional ways of escaping slashes from messages.\n // We have to 'unescape' to make it work correctly.\n args = args.map((arg) => arg.replace(/\\\\\\\\/g, \"\\\\\"));\n }\n const options = {\n ...options_,\n env: {\n LANG: \"en_US.utf-8\", // make sure to use unicode if user hasn't set LANG themselves\n EDITOR: undefined,\n GRAPHITE_INTERACTIVE: \"true\",\n },\n cwd,\n };\n\n // Hack: for pkg'd CLI, pointing to the executable at itself doesn't work. We need to treat it like a node script.\n if (!command && process.argv[1].startsWith(\"/snapshot/\")) {\n command = process.argv[0];\n args = [\"/snapshot/monologue/apps/public/cli/dist/graphite.js\", ...args];\n } else if (!command) {\n command = \"gt\";\n }\n\n // TODO: we could run with systemd for better OOM protection when on linux\n return { command, args, options };\n}\n\n/**\n * Extract CommitInfos from log calls that use FETCH_TEMPLATE.\n */\nexport function parseCommitInfoOutput(\n logger: Logger,\n output: string\n): SmartlogCommits {\n let commitInfos: Array<BranchInfo> = [];\n try {\n commitInfos = JSON.parse(output);\n } catch (err) {\n logger.error(\"failed to parse branch info\", err);\n }\n return commitInfos;\n}\nexport function parseSuccessorData(\n successorData: string\n): SuccessorInfo | undefined {\n const [successorString] = successorData.split(\",\", 1); // we're only interested in the first available mutation\n if (!successorString) {\n return undefined;\n }\n const successor = successorString.split(\":\");\n return {\n hash: successor[1],\n type: successor[0],\n };\n}\n\n/**\n * Returns absolute path for a repo-relative file path.\n * If the path \"escapes\" the repository's root dir, returns null\n * Used to validate that a file path does not \"escape\" the repo, and the file can safely be modified on the filesystem.\n * absolutePathForFileInRepo(\"foo/bar/file.txt\", repo) -> /path/to/repo/foo/bar/file.txt\n * absolutePathForFileInRepo(\"../file.txt\", repo) -> null\n */\nexport function absolutePathForFileInRepo(\n filePath: RepoRelativePath,\n repo: Repository,\n pathMod = path\n): AbsolutePath | null {\n // Note that resolve() is contractually obligated to return an absolute path.\n const fullPath = pathMod.resolve(repo.info.repoRoot, filePath);\n // Prefix checks on paths can be footguns on Windows for C:\\\\ vs c:\\\\, but since\n // we use the same exact path check here and in the resolve, there should be\n // no incompatibility here.\n if (fullPath.startsWith(repo.info.repoRoot + pathMod.sep)) {\n return fullPath;\n } else {\n return null;\n }\n}\n\nexport function repoRelativePathForAbsolutePath(\n absolutePath: AbsolutePath,\n repo: Repository,\n pathMod = path\n): RepoRelativePath {\n return pathMod.relative(repo.info.repoRoot, absolutePath);\n}\n\nfunction isProcessError(s: unknown): s is { stderr: string } {\n return s != null && typeof s === \"object\" && \"stderr\" in s;\n}\n\nfunction computeNewConflicts(\n previousConflicts: MergeConflicts,\n commandOutput: Status,\n fetchStartTimestamp: number\n): MergeConflicts | undefined {\n const newConflictData = commandOutput;\n if (!newConflictData?.conflicts) {\n return undefined;\n }\n\n const newConflicts = newConflictData.files.filter(\n (file) => file.status === \"UNRESOLVED\"\n );\n const conflicts: MergeConflicts = {\n state: \"loaded\",\n files: [],\n fetchStartTimestamp,\n fetchCompletedTimestamp: Date.now(),\n };\n if (previousConflicts?.files != null && previousConflicts.files.length > 0) {\n // we saw conflicts before, some of which might now be resolved. Preserve previous ordering.\n const newConflictSet = new Set(\n newConflicts.map((conflict) => conflict.path)\n );\n conflicts.files = previousConflicts.files.map((conflict) =>\n newConflictSet.has(conflict.path)\n ? { path: conflict.path, status: \"UNRESOLVED\" }\n : // 'R' is overloaded to mean \"removed\" for `gt status` but 'Resolved' for `gt resolve --list`\n // let's re-write this to make the UI layer simpler.\n { path: conflict.path, status: \"RESOLVED\" }\n );\n } else {\n conflicts.files = newConflicts.map((conflict) => ({\n path: conflict.path,\n status: \"UNRESOLVED\",\n }));\n }\n\n return conflicts;\n}\n","import fs from \"fs\";\nimport path from \"path\";\n\n/**\n * Check if file path exists.\n * May still throw non-ENOENT fs access errors.\n * Note: this works on Node 10.x\n */\nexport function exists(file: string): Promise<boolean> {\n return fs.promises\n .stat(file)\n .then(() => true)\n .catch((error: NodeJS.ErrnoException) => {\n if (error.code === \"ENOENT\") {\n return false;\n } else {\n throw error;\n }\n });\n}\n\n/**\n * Add a trailing path sep (/ or \\) if one does not exist\n */\nexport function ensureTrailingPathSep(p: string): string {\n if (p.endsWith(path.sep)) {\n return p;\n }\n return p + path.sep;\n}\n\n/**\n * Add a trailing path sep (/ or \\) if one does not exist\n */\nexport function removeLeadingPathSep(p: string): string {\n if (p.startsWith(path.sep)) {\n return p.slice(1);\n }\n return p;\n}\n","import type {\n AbsolutePath,\n PlatformSpecificClientToServerMessages,\n ServerToClientMessage,\n} from \"@withgraphite/gti-shared\";\nimport { unwrap } from \"@withgraphite/gti-shared\";\nimport { spawn } from \"child_process\";\nimport pathModule from \"path\";\n\nimport type { Repository } from \"./Repository\";\n\n/**\n * Platform-specific server-side API for each target: vscode extension host, electron standalone, browser, ...\n * See also platform.ts\n */\nexport interface ServerPlatform {\n platformName: string;\n handleMessageFromClient(\n repo: Repository | undefined,\n message: PlatformSpecificClientToServerMessages,\n postMessage: (message: ServerToClientMessage) => void,\n onDispose: (disapose: () => unknown) => void\n ): void | Promise<void>;\n}\n\nexport const browserServerPlatform: ServerPlatform = {\n platformName: \"browser\",\n handleMessageFromClient: (\n repo: Repository | undefined,\n message: PlatformSpecificClientToServerMessages\n ) => {\n switch (message.type) {\n case \"platform/openFile\": {\n const path: AbsolutePath = pathModule.join(\n unwrap(repo?.info.repoRoot),\n message.path\n );\n let command;\n if (command == null) {\n // use OS-builtin open command to open files\n // (which may open different file extensions with different programs)\n // TODO: add a config option to determine which program to launch\n switch (process.platform) {\n case \"darwin\":\n command = \"/usr/bin/open\";\n break;\n\n case \"win32\":\n command = \"notepad.exe\";\n break;\n\n case \"linux\":\n command = \"xdg-open\";\n break;\n\n default:\n }\n }\n if (command) {\n // Because the GTI server is likely running in the background and is\n // no longer attached to a terminal, this is designed for the case\n // where the user opens the file in a windowed editor (hence\n // `windowsHide: false`, which is the default for\n // `child_process.spawn()`, but not for `execa()`):\n //\n // - For users using a simple one-window-per-file graphical text\n // editor, like notepad.exe, this is relatively straightforward.\n // - For users who prefer a terminal-based editor, like Emacs,\n // a conduit like EmacsClient would be required.\n //\n // Further, killing GTI should not kill the editor, so this follows\n // the pattern for spawning an independent, long-running process in\n // Node.js as described here:\n //\n // https://nodejs.org/docs/latest-v10.x/api/child_process.html#child_process_options_detached\n repo?.logger.log(\"open file\", path);\n // TODO: Report error if spawn() fails?\n const proc = spawn(command, [path], {\n detached: true,\n stdio: \"ignore\",\n windowsHide: false,\n windowsVerbatimArguments: true,\n });\n // Silent error. Don't crash the server process.\n proc.on(\"error\", (err) => {\n repo?.logger.log(\"failed to open\", path, err);\n });\n proc.unref();\n }\n break;\n }\n\n default:\n }\n },\n};\n","import type {\n AbsolutePath,\n Logger,\n RepositoryError,\n ValidatedRepoInfo,\n} from \"@withgraphite/gti-shared\";\n\nimport { ensureTrailingPathSep } from \"./fs\";\nimport { Repository } from \"./Repository\";\nimport { TypedEventEmitter } from \"./TypedEventEmitter\";\n\n/**\n * Reference-counting access to a {@link Repository}, via a Promise.\n * Be sure to `unref()` when no longer needed.\n */\nexport interface RepositoryReference {\n promise: Promise<Repository | RepositoryError>;\n unref: () => unknown;\n}\n\n/**\n * We return `RepositoryReference`s synchronously before we have the Repository,\n * but reference counts should be associated with the actual async constructed Repository,\n * which is why we can't return RefCounted<Repository> directly.\n */\nclass RepositoryReferenceImpl implements RepositoryReference {\n constructor(\n public promise: Promise<Repository | RepositoryError>,\n private disposeFunc: () => void\n ) {}\n public unref() {\n if (!this.disposed) {\n this.disposed = true;\n this.disposeFunc();\n }\n }\n\n internalReference: RefCounted<Repository> | undefined;\n disposed = false;\n}\n\nclass RefCounted<T extends { dispose: () => void }> {\n constructor(public value: T) {}\n private references = 0;\n\n public isDisposed = false;\n public ref() {\n this.references++;\n }\n public getNumberOfReferences() {\n return this.references;\n }\n public dispose() {\n this.references--;\n if (!this.isDisposed && this.references === 0) {\n this.isDisposed = true;\n this.value.dispose();\n }\n }\n}\n\n/**\n * Allow re-using Repository instances by storing instances by path,\n * and controlling how Repositories are created.\n *\n * Some async work is needed to construct repositories (finding repo root dir),\n * so it's possible to duplicate some work if multiple repos are constructed at similar times.\n * We still enable Repository re-use in this case by double checking for pre-existing Repos at the last second.\n */\nclass RepositoryCache {\n // allow mocking Repository in tests\n constructor(private RepositoryType = Repository) {}\n\n /**\n * Previously distributed RepositoryReferences, keyed by repository root path\n * Note that Repositories do not define their own `cwd`, and can be re-used across cwds.\n */\n private reposByRoot = new Map<AbsolutePath, RefCounted<Repository>>();\n private activeReposEmitter = new TypedEventEmitter<\"change\", undefined>();\n\n private lookup(dirGuess: AbsolutePath): RefCounted<Repository> | undefined {\n for (const repo of this.reposByRoot.values()) {\n if (\n dirGuess === repo.value.info.repoRoot ||\n dirGuess.startsWith(ensureTrailingPathSep(repo.value.info.repoRoot))\n ) {\n if (!repo.isDisposed) {\n return repo;\n }\n }\n }\n return undefined;\n }\n\n /**\n * Create a new Repository, or re-use if one already exists.\n * Repositories are reference-counted to ensure they can be disposed when no longer needed.\n */\n getOrCreate(\n cmd: string | undefined,\n logger: Logger,\n cwd: string\n ): RepositoryReference {\n // Fast path: if this cwd is already a known repo root, we can use it directly.\n // This only works if the cwd happens to be the repo root.\n const found = this.lookup(cwd);\n if (found) {\n found.ref();\n return new RepositoryReferenceImpl(Promise.resolve(found.value), () =>\n found.dispose()\n );\n }\n\n // More typically, we can re-use a Repository among different cwds:\n\n // eslint-disable-next-line prefer-const\n let ref: RepositoryReferenceImpl;\n const lookupRepoInfoAndReuseIfPossible = async (): Promise<\n Repository | RepositoryError\n > => {\n // TODO: we should rate limit how many getRepoInfos we run at a time, and make other callers just wait.\n // this would guard against querying lots of redundant paths within the same repo.\n // This is probably not necessary right now, but would be useful for a VS Code extension where we need to query\n // individual file paths to add diff gutters.\n const repoInfo = await this.RepositoryType.getRepoInfo(cmd, logger, cwd);\n // important: there should be no `await` points after here, to ensure there is no race when re-using Repositories.\n if (repoInfo.type !== \"success\") {\n // No repository found at this root, or some other error prevents the repo from being created\n return repoInfo;\n }\n\n if (ref.disposed) {\n // If the reference is disposed, the caller gave up while waiting for the repo to be created.\n // make sure we don't create a dangling Repository.\n return {\n type: \"unknownError\",\n error: new Error(\"Repository already disposed\"),\n };\n }\n\n // Now that we've spent some async time to determine this repo's actual root,\n // we can check if we already have a reference to it saved.\n // This way, we can still re-use a Repository, and only risk duplicating `getRepoInfo` work.\n const newlyFound = this.lookup(repoInfo.repoRoot);\n if (newlyFound) {\n // if it is found now, it means either the cwd differs from the repo root (lookup fails), or\n // another instance was created at the same time and finished faster than this one (lookup failed before, but succeeds now).\n\n newlyFound.ref();\n ref.internalReference = newlyFound;\n return newlyFound.value;\n }\n\n // This is where we actually start new subscriptions and trigger work, so we should only do this\n // once we're sure we don't have a repository to re-use.\n const repo = new this.RepositoryType(\n repoInfo as ValidatedRepoInfo, // repoInfo is now guaranteed to have these root/dotdir set\n logger\n );\n\n const internalRef = new RefCounted(repo);\n internalRef.ref();\n ref.internalReference = internalRef;\n this.reposByRoot.set(repoInfo.repoRoot, internalRef);\n this.activeReposEmitter.emit(\"change\");\n return repo;\n };\n ref = new RepositoryReferenceImpl(\n lookupRepoInfoAndReuseIfPossible(),\n () => {\n if (ref.internalReference) {\n ref.internalReference.dispose();\n }\n ref.unref();\n }\n );\n return ref;\n }\n\n /**\n * Lookup a cached repository without creating a new one if it doens't exist\n */\n public cachedRepositoryForPath(path: AbsolutePath): Repository | undefined {\n const ref = this.lookup(path);\n return ref?.value;\n }\n\n public onChangeActiveRepos(\n cb: (repos: Array<Repository>) => unknown\n ): () => unknown {\n const onChange = () => {\n cb([...this.reposByRoot.values()].map((ref) => ref.value));\n };\n this.activeReposEmitter.on(\"change\", onChange);\n // start with initial repos set\n onChange();\n return () => this.activeReposEmitter.off(\"change\", onChange);\n }\n\n /** Clean up all known repos. Mostly useful for testing. */\n clearCache() {\n this.reposByRoot.forEach((value) => value.dispose());\n this.reposByRoot = new Map();\n this.activeReposEmitter.removeAllListeners();\n }\n\n public numberOfActiveServers(): number {\n let numActive = 0;\n for (const repo of this.reposByRoot.values()) {\n numActive += repo.getNumberOfReferences();\n }\n return numActive;\n }\n}\n\nexport const __TEST__ = { RepositoryCache };\n\nexport const repositoryCache = new RepositoryCache();\n","import type { ChangedFiles } from \"@withgraphite/gti-cli-shared-types\";\nimport type {\n ClientToServerMessage,\n ClientToServerMessageWithPayload,\n Disposable,\n FetchedCommits,\n FetchedUncommittedChanges,\n Logger,\n MergeConflicts,\n PlatformSpecificClientToServerMessages,\n RepositoryError,\n Result,\n ServerToClientMessage,\n} from \"@withgraphite/gti-shared\";\nimport {\n deserializeFromString,\n randomId,\n revsetArgsForComparison,\n serializeToString,\n unwrap,\n} from \"@withgraphite/gti-shared\";\nimport fs from \"fs\";\n\nimport type { ClientConnection } from \".\";\nimport type { ServerSideTracker } from \"./analytics/serverSideTracker\";\nimport { absolutePathForFileInRepo, Repository } from \"./Repository\";\nimport type { RepositoryReference } from \"./RepositoryCache\";\nimport { repositoryCache } from \"./RepositoryCache\";\nimport type { ServerPlatform } from \"./serverPlatform\";\nimport { findPublicAncestor } from \"./utils\";\n\ntype IncomingMessageWithPayload = ClientToServerMessageWithPayload;\nexport type IncomingMessage = ClientToServerMessage;\nexport type OutgoingMessage = ServerToClientMessage;\n\ntype GeneralMessage = IncomingMessage &\n (\n | { type: \"changeCwd\" }\n | { type: \"requestRepoInfo\" }\n | { type: \"requestApplicationInfo\" }\n | { type: \"fileBugReport\" }\n | { type: \"track\" }\n );\ntype WithRepoMessage = Exclude<IncomingMessage, GeneralMessage>;\n\n/**\n * Return true if a ClientToServerMessage is a ClientToServerMessageWithPayload\n */\nfunction expectsBinaryPayload(\n message: unknown\n): message is ClientToServerMessageWithPayload {\n return (\n message != null &&\n typeof message === \"object\" &&\n (message as ClientToServerMessageWithPayload).hasBinaryPayload === true\n );\n}\n\n/**\n * Message passing channel built on top of ClientConnection.\n * Use to send and listen for well-typed events with the client\n *\n * Note: you must set the current repository to start sending data back to the client.\n */\nexport class ServerToClientAPI {\n private listenersByType = new Map<\n string,\n Set<(message: IncomingMessage) => void | Promise<void>>\n >();\n private incomingListener: Disposable;\n\n /** Disposables that must be disposed whenever the current repo is changed */\n private repoDisposables: Array<Disposable> = [];\n private subscriptions = new Map<string, Disposable>();\n private activeRepoRef: RepositoryReference | undefined;\n\n private queuedMessages: Array<IncomingMessage> = [];\n private currentState:\n | { type: \"loading\" }\n | { type: \"repo\"; repo: Repository; cwd: string }\n | { type: \"error\"; error: RepositoryError } = { type: \"loading\" };\n\n private pageId = randomId();\n\n constructor(\n private platform: ServerPlatform,\n private connection: ClientConnection,\n private tracker: ServerSideTracker,\n private logger: Logger\n ) {\n // messages with binary payloads are sent as two post calls. We first get the JSON message, then the binary payload,\n // which we will reconstruct together.\n let messageExpectingBinaryFollowup: ClientToServerMessageWithPayload | null =\n null;\n this.incomingListener = this.connection.onDidReceiveMessage(\n (buf, isBinary) => {\n if (isBinary) {\n if (messageExpectingBinaryFollowup == null) {\n connection.logger?.error(\n \"Error: got a binary message when not expecting one\"\n );\n return;\n }\n // TODO: we don't handle queueing up messages with payloads...\n this.handleIncomingMessageWithPayload(\n messageExpectingBinaryFollowup,\n buf\n );\n messageExpectingBinaryFollowup = null;\n return;\n } else if (messageExpectingBinaryFollowup != null) {\n connection.logger?.error(\n \"Error: didnt get binary payload after a message that requires one\"\n );\n messageExpectingBinaryFollowup = null;\n return;\n }\n const message = buf.toString(\"utf-8\");\n const data = deserializeFromString(message) as IncomingMessage;\n if (expectsBinaryPayload(data)) {\n // remember this message, and wait to get the binary payload before handling it\n messageExpectingBinaryFollowup = data;\n return;\n }\n\n // When the client is connected, we want to immediately start listening to messages.\n // However, we can't properly respond to these messages until we have a repository set up.\n // Queue up messages until a repository is set.\n if (this.currentState.type === \"loading\") {\n this.queuedMessages.push(data);\n } else {\n try {\n this.handleIncomingMessage(data);\n } catch (err) {\n connection.logger?.error(\n \"error handling incoming message: \",\n data,\n err\n );\n }\n }\n }\n );\n }\n\n private setRepoError(error: RepositoryError) {\n this.disposeRepoDisposables();\n\n this.currentState = { type: \"error\", error };\n\n this.tracker.context.setRepo(undefined);\n\n this.processQueuedMessages();\n }\n\n private setCurrentRepo(repo: Repository, cwd: string) {\n this.disposeRepoDisposables();\n\n this.currentState = { type: \"repo\", repo, cwd };\n\n this.tracker.context.setRepo(repo);\n\n if (repo.codeReviewProvider != null) {\n this.repoDisposables.push(\n repo.codeReviewProvider.onChangeDiffSummaries((value) => {\n this.postMessage({ type: \"fetchedDiffSummaries\", summaries: value });\n })\n );\n }\n\n this.repoDisposables.push(\n repo.subscribeToHeadCommit((head) => {\n const allCommits = repo.getSmartlogCommits();\n const ancestor = findPublicAncestor(allCommits?.commits.value, head);\n this.tracker.track(\"HeadCommitChanged\", {\n extras: {\n hash: head.branch,\n public: ancestor?.branch,\n },\n });\n })\n );\n\n this.processQueuedMessages();\n }\n\n postMessage(message: OutgoingMessage) {\n void this.connection.postMessage(serializeToString(message)).catch(() => {\n // eslint-disable-next-line no-console\n console.warn(\"Failed to post message to client\");\n });\n }\n\n /** Get a repository reference for a given cwd, and set that as the active repo. */\n setActiveRepoForCwd(newCwd: string) {\n if (this.activeRepoRef !== undefined) {\n this.activeRepoRef.unref();\n }\n this.logger.info(`Setting active repo cwd to ${newCwd}`);\n // Set as loading right away while we determine the new cwd's repo\n // This ensures new messages coming in will be queued and handled only with the new repository\n this.currentState = { type: \"loading\" };\n const command = this.connection.command;\n this.activeRepoRef = repositoryCache.getOrCreate(\n command,\n this.logger,\n newCwd\n );\n void this.activeRepoRef.promise.then((repoOrError) => {\n if (repoOrError instanceof Repository) {\n this.setCurrentRepo(repoOrError, newCwd);\n } else {\n this.setRepoError(repoOrError);\n }\n });\n }\n\n dispose() {\n this.incomingListener.dispose();\n this.disposeRepoDisposables();\n\n if (this.activeRepoRef !== undefined) {\n this.activeRepoRef.unref();\n }\n }\n\n private disposeRepoDisposables() {\n this.repoDisposables.forEach((disposable) => disposable.dispose());\n this.repoDisposables = [];\n\n this.subscriptions.forEach((sub) => sub.dispose());\n this.subscriptions.clear();\n }\n\n private processQueuedMessages() {\n for (const message of this.queuedMessages) {\n try {\n this.handleIncomingMessage(message);\n } catch (err) {\n this.connection.logger?.error(\n \"error handling queued message: \",\n message,\n err\n );\n }\n }\n this.queuedMessages = [];\n }\n\n private handleIncomingMessageWithPayload(\n message: IncomingMessageWithPayload,\n payload: ArrayBuffer\n ) {\n switch (message.type) {\n case \"uploadFile\": {\n const { id, filename } = message;\n const uploadFile: null | ((value: any, opts: any) => Promise<string>) =\n null as null | ((value: any) => Promise<string>);\n if (uploadFile == null) {\n return;\n }\n this.tracker\n .operation(\"UploadImage\", \"UploadImageError\", {}, () =>\n uploadFile(unwrap(this.connection.logger), {\n filename,\n data: payload,\n })\n )\n .then((result: string) => {\n this.connection.logger?.info(\n \"sucessfully uploaded file\",\n filename,\n result\n );\n this.postMessage({\n type: \"uploadFileResult\",\n id,\n result: { value: result },\n });\n })\n .catch((error: Error) => {\n this.connection.logger?.info(\n \"error uploading file\",\n filename,\n error\n );\n this.postMessage({\n type: \"uploadFileResult\",\n id,\n result: { error },\n });\n });\n break;\n }\n }\n }\n\n private handleIncomingMessage(data: IncomingMessage) {\n this.handleIncomingGeneralMessage(data as GeneralMessage);\n const { currentState } = this;\n switch (currentState.type) {\n case \"repo\": {\n const { repo, cwd } = currentState;\n this.handleIncomingMessageWithRepo(data as WithRepoMessage, repo, cwd);\n break;\n }\n\n // If the repo is in the loading or error state, the client may still send\n // platform messages such as `platform/openExternal` that should be processed.\n case \"loading\":\n case \"error\":\n if (data.type.startsWith(\"platform/\")) {\n void this.platform.handleMessageFromClient(\n /*repo=*/ undefined,\n data as PlatformSpecificClientToServerMessages,\n (message) => this.postMessage(message),\n (dispose: () => unknown) => {\n this.repoDisposables.push({ dispose });\n }\n );\n this.notifyListeners(data);\n }\n break;\n }\n }\n\n /**\n * Handle messages which can be handled regardless of if a repo was successfully created or not\n */\n private handleIncomingGeneralMessage(data: GeneralMessage) {\n switch (data.type) {\n case \"track\": {\n this.tracker.trackData(data.data);\n break;\n }\n\n case \"changeCwd\": {\n this.setActiveRepoForCwd(data.cwd);\n break;\n }\n\n case \"requestRepoInfo\": {\n switch (this.currentState.type) {\n case \"repo\":\n this.postMessage({\n type: \"repoInfo\",\n info: this.currentState.repo.info,\n cwd: this.currentState.cwd,\n });\n break;\n\n case \"error\":\n this.postMessage({\n type: \"repoInfo\",\n info: this.currentState.error,\n });\n break;\n\n case \"loading\":\n }\n break;\n }\n\n case \"requestApplicationInfo\": {\n this.postMessage({\n type: \"applicationInfo\",\n platformName: this.platform.platformName,\n version: this.connection.version,\n });\n break;\n }\n\n case \"fileBugReport\": {\n // Internal.fileABug?.(\n // data.data,\n // data.uiState,\n // this.tracker,\n // this.logger,\n // (progress: FileABugProgress) => {\n // this.connection.logger?.info('file a bug progress: ', JSON.stringify(progress));\n // this.postMessage({type: 'fileBugReportProgress', ...progress});\n // },\n // );\n break;\n }\n }\n }\n\n /**\n * Handle messages which require a repository to have been successfully set up to run\n */\n private handleIncomingMessageWithRepo(\n data: WithRepoMessage,\n repo: Repository,\n cwd: string\n ) {\n const { logger } = repo;\n switch (data.type) {\n case \"subscribe\": {\n const { subscriptionID, kind } = data;\n switch (kind) {\n case \"uncommittedChanges\": {\n const postUncommittedChanges = (\n result: FetchedUncommittedChanges\n ) => {\n this.postMessage({\n type: \"subscriptionResult\",\n kind: \"uncommittedChanges\",\n subscriptionID,\n data: result,\n });\n };\n\n const uncommittedChanges = repo.getUncommittedChanges();\n if (uncommittedChanges != null) {\n postUncommittedChanges(uncommittedChanges);\n }\n const disposables: Array<Disposable> = [];\n\n // send changes as they come in from watchman\n disposables.push(\n repo.subscribeToUncommittedChanges(postUncommittedChanges)\n );\n // trigger a fetch on startup\n void repo.fetchUncommittedChanges();\n\n disposables.push(\n repo.subscribeToUncommittedChangesBeginFetching(() =>\n this.postMessage({\n type: \"beganFetchingUncommittedChangesEvent\",\n })\n )\n );\n this.subscriptions.set(subscriptionID, {\n dispose: () => {\n disposables.forEach((d) => d.dispose());\n },\n });\n break;\n }\n\n case \"smartlogCommits\": {\n const postSmartlogCommits = (result: FetchedCommits) => {\n this.postMessage({\n type: \"subscriptionResult\",\n kind: \"smartlogCommits\",\n subscriptionID,\n data: result,\n });\n };\n\n const smartlogCommits = repo.getSmartlogCommits();\n if (smartlogCommits != null) {\n postSmartlogCommits(smartlogCommits);\n }\n const disposables: Array<Disposable> = [];\n // send changes as they come from file watcher\n disposables.push(\n repo.subscribeToSmartlogCommitsChanges(postSmartlogCommits)\n );\n // trigger a fetch on startup\n void repo.fetchSmartlogCommits();\n\n disposables.push(\n repo.subscribeToSmartlogCommitsBeginFetching(() =>\n this.postMessage({ type: \"beganFetchingSmartlogCommitsEvent\" })\n )\n );\n\n this.subscriptions.set(subscriptionID, {\n dispose: () => {\n disposables.forEach((d) => d.dispose());\n },\n });\n break;\n }\n\n case \"mergeConflicts\": {\n const postMergeConflicts = (\n conflicts: MergeConflicts | undefined\n ) => {\n this.postMessage({\n type: \"subscriptionResult\",\n kind: \"mergeConflicts\",\n subscriptionID,\n data: conflicts,\n });\n };\n\n const mergeConflicts = repo.getMergeConflicts();\n if (mergeConflicts != null) {\n postMergeConflicts(mergeConflicts);\n }\n\n this.subscriptions.set(\n subscriptionID,\n repo.onChangeConflictState(postMergeConflicts)\n );\n break;\n }\n }\n break;\n }\n\n case \"unsubscribe\": {\n const subscription = this.subscriptions.get(data.subscriptionID);\n subscription?.dispose();\n this.subscriptions.delete(data.subscriptionID);\n break;\n }\n\n case \"runOperation\": {\n const { operation } = data;\n void repo.runOrQueueOperation(\n operation,\n (progress) => {\n this.postMessage({ type: \"operationProgress\", ...progress });\n if (progress.kind === \"queue\") {\n this.tracker.track(\"QueueOperation\", {\n extras: { operation: operation.trackEventName },\n });\n }\n },\n this.tracker,\n cwd\n );\n break;\n }\n\n case \"abortRunningOperation\": {\n const { operationId } = data;\n repo.abortRunningOpeation(operationId);\n break;\n }\n\n case \"getConfig\": {\n void repo\n .getConfig(data.name)\n .catch(() => undefined)\n .then((value) => {\n logger.info(\"got config\", data.name, value);\n this.postMessage({ type: \"gotConfig\", name: data.name, value });\n });\n break;\n }\n\n case \"fetchRepoMessage\": {\n const repoMessage: Promise<Result<string>> = repo\n .runCommand([\"internal-only\", \"repo-message\"])\n .then((o) => ({ value: o.stdout }))\n .catch((error) => {\n logger?.error(\"error fetching repo message\", error.toString());\n return { error };\n });\n void repoMessage.then((data) =>\n this.postMessage({\n type: \"fetchedRepoMessage\",\n message: data.value || \"\",\n })\n );\n break;\n }\n\n case \"fetchUpgradePrompt\": {\n const upgradePrompt: Promise<Result<string>> = repo\n .runCommand([\"internal-only\", \"upgrade-prompt\"])\n .then((o) => ({ value: o.stdout }))\n .catch((error) => {\n logger?.error(\"error fetching upgrade prompt\", error.toString());\n return { error };\n });\n void upgradePrompt.then((data) =>\n this.postMessage({\n type: \"fetchedUpgradePrompt\",\n message: data.value || \"\",\n })\n );\n break;\n }\n\n case \"setConfig\": {\n logger.info(\"set config\", data.name, data.value);\n repo.setConfig(\"user\", data.name, data.value).catch((err) => {\n logger.error(\"error setting config\", data.name, data.value, err);\n });\n break;\n }\n\n case \"deleteFile\": {\n const { filePath } = data;\n const absolutePath = absolutePathForFileInRepo(filePath, repo);\n // security: don't trust client messages to allow us to delete files outside the repository\n if (absolutePath == null) {\n logger.warn(\"can't delete file outside of the repo\", filePath);\n return;\n }\n\n fs.promises\n .rm(absolutePath)\n .then(() => {\n logger.info(\"deleted file from filesystem\", absolutePath);\n })\n .catch((err) => {\n logger.error(\"unable to delete file\", absolutePath, err);\n });\n break;\n }\n\n case \"requestComparison\": {\n const { comparison } = data;\n const diff: Promise<Result<string>> = repo\n .runCommand([\n \"internal-only\",\n \"diff\",\n ...revsetArgsForComparison(comparison),\n ])\n .then((o) => ({ value: o.stdout }))\n .catch((error) => {\n logger?.error(\"error running diff\", error.toString());\n return { error };\n });\n void diff.then((data) =>\n this.postMessage({\n type: \"comparison\",\n comparison,\n data: { diff: data },\n })\n );\n break;\n }\n\n case \"requestChangedFiles\": {\n const { branch } = data;\n const resultPromise: Promise<ChangedFiles> = repo\n .runCommand([\"internal-only\", \"changed-files\", branch])\n .then((o) => JSON.parse(o.stdout))\n .catch((error) => {\n logger?.error(\"error running diff\", error.toString());\n return { error };\n });\n void resultPromise.then((result) =>\n this.postMessage({\n type: \"changedFiles\",\n branch,\n data: result,\n })\n );\n break;\n }\n\n case \"requestComparisonContextLines\": {\n const {\n id: { path: relativePath, comparison },\n start,\n numLines,\n } = data;\n\n // TODO: For context lines, before/after sides of the comparison\n // are identical... except for line numbers.\n // Typical comparisons with '.' would be much faster (nearly instant)\n // by reading from the filesystem rather than using cat,\n // we just need the caller to ask with \"after\" line numbers instead of \"before\".\n // Note: we would still need to fall back to cat for comparisons that do not involve\n // the working copy.\n const cat: Promise<string> = repo\n .cat(relativePath, comparison)\n .catch(() => \"\");\n\n void cat.then((content) =>\n this.postMessage({\n type: \"comparisonContextLines\",\n lines: content.split(\"\\n\").slice(start - 1, start - 1 + numLines),\n path: relativePath,\n })\n );\n break;\n }\n\n case \"refresh\": {\n logger?.log(\"refresh requested\");\n void repo.fetchSmartlogCommits();\n void repo.fetchUncommittedChanges();\n void repo.codeReviewProvider?.triggerDiffSummariesFetch(\n repo.getAllDiffIds()\n );\n break;\n }\n\n case \"pageVisibility\": {\n repo.setPageFocus(this.pageId, data.state);\n break;\n }\n\n case \"fetchCommitMessageTemplate\": {\n repo\n .runCommand([\"internal-only\", \"templates\"])\n .then((result) => {\n const templates: Record<string, string> = JSON.parse(result.stdout);\n this.postMessage({\n type: \"fetchedCommitMessageTemplate\",\n templates: Object.fromEntries(\n Object.entries(templates).map(([path, contents]) => [\n path,\n contents.replace(repo.IGNORE_COMMIT_MESSAGE_LINES_REGEX, \"\"),\n ])\n ),\n });\n })\n .catch((err) => {\n logger?.error(\"Could not fetch commit message template\", err);\n });\n break;\n }\n\n case \"typeahead\": {\n // Current repo's code review provider should be able to handle all\n // TypeaheadKinds for the fields in its defined schema.\n void repo.codeReviewProvider\n ?.typeahead?.(data.kind, data.query)\n ?.then((result) =>\n this.postMessage({\n type: \"typeaheadResult\",\n id: data.id,\n result,\n })\n );\n break;\n }\n\n case \"fetchDiffSummaries\": {\n void repo.codeReviewProvider?.triggerDiffSummariesFetch(\n repo.getAllDiffIds()\n );\n break;\n }\n\n case \"loadMoreCommits\": {\n const rangeInDays = repo.nextVisibleCommitRangeInDays();\n this.postMessage({ type: \"commitsShownRange\", rangeInDays });\n this.postMessage({ type: \"beganLoadingMoreCommits\" });\n void repo.fetchSmartlogCommits();\n this.tracker.track(\"LoadMoreCommits\", {\n extras: { daysToFetch: rangeInDays ?? \"Infinity\" },\n });\n return;\n }\n\n default: {\n void this.platform.handleMessageFromClient(\n repo,\n data,\n (message) => this.postMessage(message),\n (dispose: () => unknown) => {\n this.repoDisposables.push({ dispose });\n }\n );\n break;\n }\n }\n\n this.notifyListeners(data);\n }\n\n private notifyListeners(data: IncomingMessage): void {\n const listeners = this.listenersByType.get(data.type);\n if (listeners) {\n listeners.forEach((handle) => handle(data));\n }\n }\n}\n","import { unwrap } from \"@withgraphite/gti-shared\";\nimport fs from \"fs\";\nimport os from \"os\";\nimport path from \"path\";\n\nimport rmtree from \"./rmtree\";\n\nexport type ExistingServerInfo = {\n sensitiveToken: string;\n challengeToken: string;\n logFileLocation: string;\n /** Which command name was used to launch this server instance,\n * so it can be propagated to run further gt commands by the server.\n * Usually, \"gt\". */\n command?: string;\n /**\n * `gt version` string. If the version of gt changes, we shouldn't re-use that server instance,\n * due to potential incompatibilities between the old running server javascript and the new client javascript.\n */\n gtVersion: string;\n};\n\nconst cacheDir =\n process.platform == \"win32\"\n ? path.join(unwrap(process.env.LOCALAPPDATA), \"cache\")\n : process.platform == \"darwin\"\n ? path.join(os.homedir(), \"Library/Caches\")\n : process.env.XDG_CACHE_HOME || path.join(os.homedir(), \".cache\");\n\n/**\n * Per-user cache dir with restrictive permissions.\n * Inside this folder will be a number of files, one per port for an active GTI server.\n */\nconst savedActiveServerUrlsDirectory = path.join(cacheDir, \"graphite-gti\");\n\nfunction fileNameForPort(port: number): string {\n return `reusable_server_${port}`;\n}\n\nfunction isMode700(stat: fs.Stats): boolean {\n // eslint-disable-next-line no-bitwise\n return (stat.mode & 0o777) === 0o700;\n}\n\n/**\n * Make a temp directory with restrictive permissions where we can write existing server information.\n * Ensures directory has proper restrictive mode if the directory already exists.\n */\nexport async function ensureExistingServerFolder(): Promise<void> {\n await fs.promises.mkdir(savedActiveServerUrlsDirectory, {\n // directory needs rwx\n mode: 0o700,\n recursive: true,\n });\n\n const stat = await fs.promises.stat(savedActiveServerUrlsDirectory);\n if (process.platform !== \"win32\" && !isMode700(stat)) {\n throw new Error(\n `active servers folder ${savedActiveServerUrlsDirectory} has the wrong permissions: ${stat.mode}`\n );\n }\n if (stat.isSymbolicLink()) {\n throw new Error(\n `active servers folder ${savedActiveServerUrlsDirectory} is a symlink`\n );\n }\n}\n\nexport function deleteExistingServerFile(port: number): Promise<void> {\n const folder = path.join(\n savedActiveServerUrlsDirectory,\n fileNameForPort(port)\n );\n if (typeof fs.promises.rm === \"function\") {\n return fs.promises.rm(folder, { force: true });\n } else {\n return rmtree(folder);\n }\n}\n\nexport async function writeExistingServerFile(\n port: number,\n data: ExistingServerInfo\n): Promise<void> {\n await fs.promises.writeFile(\n path.join(savedActiveServerUrlsDirectory, fileNameForPort(port)),\n JSON.stringify(data),\n { encoding: \"utf-8\", flag: \"w\", mode: 0o600 }\n );\n}\n\nexport async function readExistingServerFile(\n port: number\n): Promise<ExistingServerInfo> {\n // TODO: do we need to verify the permissions of this file?\n const data: string = await fs.promises.readFile(\n path.join(savedActiveServerUrlsDirectory, fileNameForPort(port)),\n { encoding: \"utf-8\", flag: \"r\" }\n );\n return JSON.parse(data) as ExistingServerInfo;\n}\n","import { timingSafeEqual } from \"crypto\";\n\n/**\n * Timing safe comparison of tokens coming from strings.\n */\nexport function areTokensEqual(a: string, b: string): boolean {\n const aBuf = Buffer.from(a);\n const bBuf = Buffer.from(b);\n return aBuf.length === bBuf.length && timingSafeEqual(aBuf, bBuf);\n}\n","import type { Logger } from \"@withgraphite/gti-shared\";\n\nimport { makeServerSideTracker } from \"./analytics/serverSideTracker\";\nimport { fileLogger, stdoutLogger } from \"./logger\";\nimport { runCommand } from \"./Repository\";\nimport type { ServerPlatform } from \"./serverPlatform\";\nimport { browserServerPlatform } from \"./serverPlatform\";\nimport { ServerToClientAPI } from \"./ServerToClientAPI\";\n\nexport { DEFAULT_PORT, runProxyMain } from \"../proxy/startServer\";\n\nexport interface ClientConnection {\n /**\n * Used to send a message from the server to the client.\n *\n * Designed to match\n * https://code.visualstudio.com/api/references/vscode-api#Webview.postMessage\n */\n postMessage(message: string): Promise<boolean>;\n\n /**\n * Designed to match\n * https://code.visualstudio.com/api/references/vscode-api#Webview.onDidReceiveMessage\n */\n onDidReceiveMessage(\n hander: (event: Buffer, isBinary: boolean) => void | Promise<void>\n ): {\n dispose(): void;\n };\n\n /**\n * Which command to use to run `gt`\n */\n command?: string;\n /**\n * Platform-specific version string.\n * For `gt interactive web`, this is the `gt` version.\n * For the VS Code extension, this is the extension version.\n */\n version: string;\n logFileLocation?: string;\n logger?: Logger;\n cwd: string;\n\n platform?: ServerPlatform;\n}\n\nexport function onClientConnection(connection: ClientConnection): () => void {\n const logger =\n connection.logger ??\n (connection.logFileLocation\n ? fileLogger(connection.logFileLocation)\n : stdoutLogger);\n connection.logger = logger;\n const platform = connection?.platform ?? browserServerPlatform;\n const version = connection?.version ?? \"unknown\";\n logger.log(`establish client connection for ${connection.cwd}`);\n logger.log(`platform '${platform.platformName}', version '${version}'`);\n\n const tracker = makeServerSideTracker(logger, platform, version, (data) => {\n return runCommand({\n command: connection.command || \"gt\",\n args: [\n \"internal-only\",\n \"log-action\",\n data.eventName || data.errorName || \"UNKNOWN_CLI_EVENT\",\n (data.timestamp ? new Date(data.timestamp) : new Date()).toISOString(),\n JSON.stringify(data),\n ],\n cwd: connection.cwd,\n });\n });\n tracker.track(\"ClientConnection\", { extras: { cwd: connection.cwd } });\n\n // start listening to messages\n let api: ServerToClientAPI | null = new ServerToClientAPI(\n platform,\n connection,\n tracker,\n logger\n );\n api.setActiveRepoForCwd(connection.cwd);\n\n return () => {\n api?.dispose();\n api = null;\n };\n}\n","import type { PlatformName } from \"@withgraphite/gti-shared\";\nimport { CLOSED_AND_SHOULD_NOT_RECONNECT_CODE } from \"@withgraphite/gti-shared\";\nimport fs from \"fs\";\nimport http from \"http\";\nimport type { AddressInfo } from \"net\";\nimport path from \"path\";\nimport urlModule from \"url\";\nimport WebSocket from \"ws\";\n\nimport { onClientConnection } from \"../src/index\";\nimport { repositoryCache } from \"../src/RepositoryCache\";\nimport type { ServerPlatform } from \"../src/serverPlatform\";\nimport { areTokensEqual } from \"./proxyUtils\";\n\nexport type StartServerArgs = {\n port: number;\n sensitiveToken: string;\n challengeToken: string;\n logFileLocation: string;\n logInfo: (...args: Parameters<typeof console.log>) => void;\n command?: string;\n gtVersion: string;\n foreground: boolean;\n frontendDir: string;\n};\n\nexport type StartServerResult =\n | { type: \"addressInUse\" }\n | { type: \"success\"; port: number; pid: number }\n | { type: \"error\"; error: string };\n\nexport type ServerChallengeResponse = {\n challengeToken: string;\n /** Process ID for the server. */\n pid: number;\n};\n\nexport function startServer({\n port,\n sensitiveToken,\n challengeToken,\n logFileLocation,\n logInfo,\n command,\n gtVersion,\n foreground,\n frontendDir,\n}: StartServerArgs): Promise<StartServerResult> {\n return new Promise((resolve) => {\n try {\n const manifest = JSON.parse(\n fs.readFileSync(\n path.join(frontendDir, \"build/asset-manifest.json\"),\n \"utf-8\"\n )\n ) as { files: Array<string> };\n for (const file of Object.values(manifest.files)) {\n if (!file.startsWith(\"/\")) {\n resolve({\n type: \"error\",\n error: `expected entry to start with / but was: \\`${file}\\``,\n });\n }\n\n requestUrlToResource[file] = file.slice(1);\n }\n } catch (e) {\n // ignore...\n }\n\n // Anything not part of the asset-manifest we need to explicitly serve\n requestUrlToResource[`/favicon.ico`] = \"favicon.ico\";\n\n /**\n * Event listener for HTTP server \"error\" event.\n */\n function onError(error: { syscall?: string; code?: string }) {\n if (error.syscall !== \"listen\") {\n resolve({ type: \"error\", error: error.toString() });\n throw error;\n }\n\n // handle specific listen errors with friendly messages\n switch (error.code) {\n case \"EACCES\": {\n resolve({\n type: \"error\",\n error: `Port ${port} requires elevated privileges`,\n });\n throw error;\n }\n\n case \"EADDRINUSE\": {\n resolve({ type: \"addressInUse\" });\n return;\n }\n\n default:\n resolve({ type: \"error\", error: error.toString() });\n throw error;\n }\n }\n\n /**\n * Create HTTP server.\n */\n const server = http.createServer(async (req, res) => {\n if (req.url) {\n // Only the websocket is sensitive and requires the token.\n // Normal resource requests don't need to check the token.\n const { pathname } = urlModule.parse(req.url);\n // eslint-disable-next-line no-prototype-builtins\n if (pathname != null && requestUrlToResource.hasOwnProperty(pathname)) {\n const relativePath = requestUrlToResource[pathname];\n let contents: string | Buffer;\n try {\n contents = await fs.promises.readFile(\n path.join(frontendDir, \"build\", relativePath)\n );\n } catch (e: unknown) {\n res.writeHead(500, { \"Content-Type\": \"text/plain\" });\n res.end(htmlEscape((e as Error).toString()));\n return;\n }\n\n const lastDot = relativePath.lastIndexOf(\".\");\n const ext = relativePath.slice(lastDot + 1);\n const contentType = extensionToMIMEType[ext] ?? \"text/plain\";\n\n res.writeHead(200, { \"Content-Type\": contentType });\n res.end(contents);\n return;\n } else if (pathname === \"/challenge_authenticity\") {\n // requests to /challenge_authenticity?token=... allow using the sensistive token to ask\n // for the secondary challenge token.\n const requestToken = getSearchParams(req.url).get(\"token\");\n if (requestToken && areTokensEqual(requestToken, sensitiveToken)) {\n // they know the original token, we can tell them our challenge token\n res.writeHead(200, { \"Content-Type\": \"text/json\" });\n const response: ServerChallengeResponse = {\n challengeToken,\n pid: process.pid,\n };\n res.end(JSON.stringify(response));\n } else {\n res.writeHead(401, { \"Content-Type\": \"text/json\" });\n res.end(JSON.stringify({ error: \"invalid token\" }));\n }\n return;\n }\n }\n\n res.writeHead(404, { \"Content-Type\": \"text/html\" });\n res.end(\"<html><body>Not Found!</body></html>\");\n });\n\n /**\n * Listen on provided port, on all network interfaces.\n */\n const httpServer = server.listen(port);\n const wsServer = new WebSocket.Server({ noServer: true, path: \"/ws\" });\n wsServer.on(\"connection\", (socket, connectionRequest) => {\n // We require websocket connections to contain the token as a URL search parameter.\n let providedToken: string | undefined;\n let cwd: string | undefined;\n let platform: string | undefined;\n if (connectionRequest.url) {\n const searchParams = getSearchParams(connectionRequest.url);\n providedToken = searchParams.get(\"token\");\n const cwdParam = searchParams.get(\"cwd\");\n platform = searchParams.get(\"platform\") as string;\n if (cwdParam) {\n cwd = decodeURIComponent(cwdParam);\n }\n }\n if (!providedToken) {\n const reason = \"No token provided in websocket request\";\n logInfo(\"closing ws:\", reason);\n socket.close(CLOSED_AND_SHOULD_NOT_RECONNECT_CODE, reason);\n return;\n }\n if (!areTokensEqual(providedToken, sensitiveToken)) {\n const reason = \"Invalid token\";\n logInfo(\"closing ws:\", reason);\n socket.close(CLOSED_AND_SHOULD_NOT_RECONNECT_CODE, reason);\n return;\n }\n\n const platformImpl: ServerPlatform | undefined = undefined;\n switch (platform as PlatformName) {\n default:\n case undefined:\n break;\n }\n\n const dispose = onClientConnection({\n postMessage(message: string | ArrayBuffer) {\n socket.send(message);\n return Promise.resolve(true);\n },\n onDidReceiveMessage(handler) {\n const emitter = socket.on(\"message\", handler);\n const dispose = () => emitter.off(\"message\", handler);\n return { dispose };\n },\n cwd: cwd ?? process.cwd(),\n logFileLocation:\n logFileLocation === \"stdout\" ? undefined : logFileLocation,\n command,\n version: gtVersion,\n\n platform: platformImpl,\n });\n socket.on(\"close\", () => {\n dispose();\n\n // After disposing, we may not have anymore servers alive anymore.\n // We can proactively clean up the server so you get the latest version next time you try.\n // This way, we only re-use servers if you keep the tab open.\n // Note: since we trigger this cleanup on dispose, if you start a server with `--no-open`,\n // it won't clean itself up until you connect at least once.\n if (!foreground) {\n // We do this on a 1-minute delay in case you close a tab and quickly re-open it.\n setTimeout(() => {\n checkIfServerShouldCleanItselfUp();\n }, 60_000);\n }\n });\n });\n httpServer.on(\"upgrade\", (request, socket, head) => {\n wsServer.handleUpgrade(request, socket, head, (socket) => {\n wsServer.emit(\"connection\", socket, request);\n });\n });\n\n server.on(\"error\", onError);\n\n // return succesful result when the server is successfully listening\n server.on(\"listening\", () =>\n resolve({\n type: \"success\",\n port: (server.address() as AddressInfo).port,\n pid: process.pid,\n })\n );\n });\n}\n\nfunction checkIfServerShouldCleanItselfUp() {\n if (repositoryCache.numberOfActiveServers() === 0) {\n process.exit(0);\n }\n}\n\nfunction getSearchParams(url: string): Map<string, string> {\n const searchParamsArray = urlModule\n .parse(url)\n .search?.replace(/^\\?/, \"\")\n .split(\"&\")\n .map(\n (pair: string): [string, string] => pair.split(\"=\") as [string, string]\n );\n\n return new Map(searchParamsArray);\n}\n\nconst extensionToMIMEType: { [key: string]: string } = {\n css: \"text/css\",\n html: \"text/html\",\n js: \"text/javascript\",\n ttf: \"font/ttf\",\n};\n\nconst requestUrlToResource: { [key: string]: string } = {\n \"/\": \"index.html\",\n};\n\nfunction htmlEscape(str: string): string {\n return str\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\")\n .replace(/'/g, \"\");\n}\n"],"names":["ComparisonType","exports","comparison","type","UncommittedChanges","HeadChanges","StackChanges","Committed","hash","LRU","constructor","maxItems","maxHashCollision","Map","get","key","result","hashKey","getHashKey","valueMap","cache","undefined","maybeValue","k","v","delete","set","value","size","next","keys","done","clear","hashCodeFunc","hashCode","apply","cachedFunction","func","opts","_a","cacheSize","_b","getExtraKeys","cachedFunc","args","stats","every","isCachable","skip","cacheKey","cachedValue","hit","miss","_c","arg1","arg2","Object","values","filter","_target","_propertyKey","descriptor","originalFunc","cacheDecorator","cachableTypeNames","Set","arg","typeName","has","__exportStar","Tracker","sendData","context","error","eventName","errorName","data","errorMessage","Error","message","String","track","operation","startTime","Date","now","id","parentId","then","finalResult","duration","catch","err","Promise","reject","trackAsParent","trackData","childData","ctx","timestamp","AbortController","node_abort_controller_1","wait","leading","timeout","shouldCallLeading","debouncer","callback","clearTimeout","setTimeout","reset","isPending","SelfUpdate","inner","equals","other","otherInner","paths","options","pathObjects","map","path","separator","replace","length","guessSeparator","rootPrefixResult","exec","rootPrefix","depth","parts","split","reverse","part","hadLeadingSeparator","startsWith","maxDepth","Math","max","pathObject","pathObjectsToProcess","groupedPathObjects","currentDepth","slice","join","add","pathObjectGroup","Array","from","resultPathParts","alwaysShowLeadingSeparator","DiffType","DIFF","RENAME_FROM","RENAME_TO","COPY_FROM","COPY_TO","NEW_FILE_MODE","DELETED_FILE_MODE","OLD_MODE","NEW_MODE","HUNK_HEADER","OLD_FILE_HEADER","NEW_FILE_HEADER","DELIMITERS","assert","condition","msg","patch","diffstr","delimiters","match","list","i","parseIndex","index","hunks","push","line","header","oldFileName","newFileName","parseHeader","test","parseOldMode","parseNewMode","parseDeletedFileMode","parseNewFileMode","parseCopy","parseRename","parseFileHeader","parseHunk","parseHunks","arr","oldMode","Modified","newMode","Removed","Added","Copied","Renamed","hunkHeader","hunk","oldStart","oldLines","newStart","newLines","lines","linedelimiters","addCount","removeCount","indexOf","UNDEFINED_SERIALIZED","__rpcType","serialize","entries","val","stack","valueOf","isArray","a","newObj","propertyName","propertyValue","deserialize","specific","e","standardObject","JSON","stringify","parse","CommandRunner","revset","ErrorShortMessages","toString","random","deferred","promise","resolve","s","delimiter","foundIndex","lastIndexOf","start","className","el","classList","contains","parentElement","o","fromEntries","gen","iter1","iter2","iterator1","Symbol","iterator","iterator2","result1","result2","text","maxLength","substring","getUsername","username","osInfoError","env","process","unwrap","LOGNAME","USER","LNAME","USERNAME","processEnvError","ServerSideContext","logger","setRepo","repo","this","codeReviewProvider","getSummaryName","noOp","_data","stdoutLogger","console","TypedEventEmitter","EventEmitter","GitHubCodeReviewProvider","codeReviewSystem","runCommand","diffSummaries","onChangeDiffSummaries","handleData","handleError","on","dispose","off","async","_diffs","prs","stdout","emit","removeAllListeners","hostname","owner","runExternalCommand","_cwd","_args","_onProgress","_signal","_kind","_query","OperationQueue","runCallback","queuedOperations","runningOperation","abortController","onProgress","tracker","cwd","kind","queue","handleCommandProgress","op","exitCode","controller","newAbortController","trackEventName","extras","runner","_p","signal","shift","runOrQueueOperation","errString","log","abortRunningOperation","operationId","abort","PageFocusTracker","focusedPages","visiblePages","onChangeHandlers","setState","page","state","handler","disposePage","hasPageWithFocus","hasVisiblePage","onChange","RateLimiter","maxSimultaneousRunning","queued","running","runs","nextId","generateId","tryDequeueNext","includes","res","ran","notifyFinished","toRun","run","sleep","timeMs","serializeAsyncCall","asyncFun","scheduledCall","pendingCall","startAsyncCall","resultPromise","callNext","scheduleNextCall","Watchman","client","serializedReconnect","reconnectDelayMs","subscriptions","lastKnownClockTimes","status","watchmanBinaryPath","initWatchmanClient","tries","reconnectClient","warn","info","setStatus","localDirectoryPath","rawSubscriptionName","subscriptionOptions","subscriptionName","fixupName","existingSubscription","getSubscription","subscriptionCount","watch","watchRoot","relative_path","relativePath","watchProject","clock","fields","since","relative_root","empty_on_fresh_instance","subscription","root","pathFromSubscriptionRootToSubscriptionPath","name","emitter","setSubscription","subscribe","unsubscribe","deleteSubscription","statusBeforeError","end","onSubscriptionResult","bind","restoreSubscriptions","watchSubscriptions","numSubscriptions","numRestored","all","entryPath","response","is_fresh_instance","files","canceled","stateEnter","stateLeave","stateMessage","subscriptionPath","command","directoryPath","warning","DEFAULT_POLL_INTERVAL","ONE_MINUTE_MS","VISIBLE_POLL_INTERVAL","FOCUSED_POLL_INTERVAL","WatchForChanges","repoInfo","pageFocusTracker","changeCallback","static","watchman","disposables","setupWatchmanSubscriptions","setupPolling","poll","lastFetch","desiredNextTickTime","elapsedTickTime","repoRoot","dotdir","relativeDotdir","FILE_CHANGE_WATCHMAN_SUBSCRIPTION","DIRSTATE_WATCHMAN_SUBSCRIPTION","handleRepositoryStateChange","debounce","dirstateSubscription","watchDirectoryRecursive","expression","defer","WATCHMAN_DEFER","changes","handleUncommittedChanges","uncommittedChangesSubscription","unwatch","forEach","MIN_REQUIRED_CLI_VERSION","Repository","IGNORE_COMMIT_MESSAGE_LINES_REGEX","mergeConflicts","uncommittedChanges","smartlogCommits","mergeConflictsEmitter","uncommittedChangesEmitter","smartlogCommitsChangesEmitter","smartlogCommitsBeginFetchingEmitter","uncommittedChangesBeginFetchingEmitter","onDidDispose","operationQueue","watchForChanges","currentVisibleCommitRangeIndex","visibleCommitRanges","DEFAULT_DAYS_OF_COMMITS_TO_LOAD","remote","fetchUncommittedChanges","fetchSmartlogCommits","checkForMergeConflicts","Graphite","runOperation","CodeReviewProvider","normalizedArgs","normalizeOperationArgs","seenDiffs","subscribeToSmartlogCommitsChanges","fetched","commits","newDiffs","diffIds","commit","pr","number","diffId","triggerDiffSummariesFetch","getAllDiffIds","nextVisibleCommitRangeInDays","onChangeConflictState","wasAlreadyInConflicts","file","stat","code","fetchStartTimestamp","output","proc","previousConflicts","commandOutput","newConflictData","conflicts","newConflicts","fetchCompletedTimestamp","newConflictSet","conflict","computeNewConflicts","maxConflictsToLog","remainingConflicts","getMergeConflicts","repoVersion","findVersion","versionFound","versionRequired","profile","repoInfoRaw","preferredBranchEdit","createPrsAs","findRepoProfile","findRepoInfo","getConfig","dotDir","rootDir","trunkBranch","abortRunningOpeation","cwdRelativeArgs","stdin","getExecParams","input","execution","stderr","addEventListener","child","kill","forceKillAfterTimeout","handleAbortSignalOnProcess","setPageFocus","getUncommittedChanges","subscribeToUncommittedChanges","change","p","getSmartlogCommits","subscribeToSmartlogCommitsBeginFetching","onStart","subscribeToUncommittedChangesBeginFetching","commitInfos","parseCommitInfoOutput","trim","NoCommitsFetched","subscribeToHeadCommit","headCommit","find","isHead","onData","newHead","branch","catLimiter","cat","enqueueRun","catArgs","stripFinalNewline","notEmpty","configName","setConfig","level","configValue","command_","args_","options_","appUrl","platform","LANG","EDITOR","GRAPHITE_INTERACTIVE","argv","browserServerPlatform","platformName","handleMessageFromClient","spawn","detached","stdio","windowsHide","windowsVerbatimArguments","unref","RepositoryReferenceImpl","disposeFunc","disposed","internalReference","RefCounted","references","isDisposed","ref","getNumberOfReferences","repositoryCache","RepositoryType","reposByRoot","activeReposEmitter","lookup","dirGuess","endsWith","getOrCreate","cmd","found","getRepoInfo","newlyFound","internalRef","lookupRepoInfoAndReuseIfPossible","cachedRepositoryForPath","onChangeActiveRepos","cb","clearCache","numberOfActiveServers","numActive","ServerToClientAPI","connection","listenersByType","incomingListener","repoDisposables","activeRepoRef","queuedMessages","currentState","pageId","randomId","messageExpectingBinaryFollowup","onDidReceiveMessage","buf","isBinary","handleIncomingMessageWithPayload","deserializeFromString","hasBinaryPayload","expectsBinaryPayload","handleIncomingMessage","setRepoError","disposeRepoDisposables","processQueuedMessages","setCurrentRepo","postMessage","summaries","head","allCommits","ancestor","publicCommit","current","partOfTrunk","parents","findPublicAncestor","public","serializeToString","setActiveRepoForCwd","newCwd","repoOrError","disposable","sub","payload","filename","uploadFile","handleIncomingGeneralMessage","handleIncomingMessageWithRepo","notifyListeners","version","subscriptionID","postUncommittedChanges","d","postSmartlogCommits","postMergeConflicts","progress","filePath","absolutePath","pathMod","fullPath","sep","absolutePathForFileInRepo","rm","revsetArgsForComparison","diff","numLines","content","templates","contents","typeahead","query","rangeInDays","daysToFetch","listeners","handle","cacheDir","LOCALAPPDATA","XDG_CACHE_HOME","b","aBuf","Buffer","bBuf","timingSafeEqual","onClientConnection","logFileLocation","str","appendFile","getLogFileContents","readFile","fileLogger","writeToServer","sessionId","unixname","osArch","osType","osRelease","generateAnalyticsInfo","makeServerSideTracker","toISOString","api","startServer","port","sensitiveToken","challengeToken","logInfo","gtVersion","foreground","frontendDir","manifest","requestUrlToResource","server","req","url","pathname","hasOwnProperty","writeHead","lastDot","ext","contentType","extensionToMIMEType","requestToken","getSearchParams","pid","httpServer","listen","wsServer","noServer","socket","connectionRequest","providedToken","searchParams","cwdParam","decodeURIComponent","reason","close","CLOSED_AND_SHOULD_NOT_RECONNECT_CODE","send","exit","request","handleUpgrade","syscall","address","searchParamsArray","search","pair","css","html","js","ttf"],"sourceRoot":""}
|