@myagentroam/node 0.11.0 → 0.11.2

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.
@@ -1,5 +1,6 @@
1
1
  import { createHash } from 'node:crypto';
2
- import { listGitHistoryRefs, openGitHistoryFileContent, readGitHistory, readGitHistoryFileDiff, readGitHistoryFileContentRange, readGitHistoryFiles, readCurrentChangeDiff, readRestrictedDiff, resolveGitRepository, resolveGitRepositoryTarget, restoreCurrentChange } from '../workspace.js';
2
+ import { isAbsolute, win32 } from 'node:path';
3
+ import { listGitHistoryRefs, normalizeFilePreviewPath, openGitHistoryFileContent, readGitHistory, readGitHistoryFileDiff, readGitHistoryFileContentRange, readGitHistoryFiles, readCurrentChangeDiff, readRestrictedDiff, resolveGitRepository, resolveGitRepositoryTarget, resolveWorkspaceGitRoot, restoreCurrentChange } from '../workspace.js';
3
4
  import { WorkspaceCodeNavigationService } from './workspace-code-navigation-service.js';
4
5
  import { WorkspaceContentSearchService } from './workspace-content-search-service.js';
5
6
  import { WorkspaceWatchController } from './workspace-watch-controller.js';
@@ -98,7 +99,7 @@ export class WorkspaceWorkbenchService {
98
99
  }
99
100
  async readPredictionFile(workspaceId, path, worktreePath) {
100
101
  const workspace = this.options.requireWorkspace(workspaceId);
101
- const repository = await this.fileRepository(workspace, worktreePath ? { worktreePath } : {});
102
+ const repository = await this.fileRepository(workspace, worktreePath ? { worktreePath, path } : {});
102
103
  const { readWorkspaceTextFile } = await import('../workspace.js');
103
104
  return readWorkspaceTextFile(repository, path, 0, 64 * 1024);
104
105
  }
@@ -180,7 +181,7 @@ export class WorkspaceWorkbenchService {
180
181
  (input.worktreePath !== undefined && typeof input.worktreePath !== 'string'))
181
182
  throw new Error('GIT_DIFF_INVALID');
182
183
  const workspace = this.gitWorkspace(input.workspaceId);
183
- const repository = await resolveGitRepositoryTarget(workspace.path, input.repositoryPath ?? '', input.worktreePath);
184
+ const repository = await resolveGitRepositoryTarget(await resolveWorkspaceGitRoot(workspace.path, workspace.includeParentRepository ?? true), input.repositoryPath ?? '', input.worktreePath);
184
185
  return { diff: await readCurrentChangeDiff(repository, input.path) };
185
186
  }
186
187
  async restoreChange(input) {
@@ -191,7 +192,7 @@ export class WorkspaceWorkbenchService {
191
192
  (input.state !== 'STAGED' && input.state !== 'UNSTAGED' && input.state !== 'UNTRACKED'))
192
193
  throw new Error('GIT_CHANGE_RESTORE_UNAVAILABLE');
193
194
  const workspace = this.gitWorkspace(input.workspaceId);
194
- const repository = await resolveGitRepositoryTarget(workspace.path, input.repositoryPath ?? '', input.worktreePath);
195
+ const repository = await resolveGitRepositoryTarget(await resolveWorkspaceGitRoot(workspace.path, workspace.includeParentRepository ?? true), input.repositoryPath ?? '', input.worktreePath);
195
196
  await restoreCurrentChange(repository, input.path, input.state);
196
197
  this.options.invalidate(workspace.id);
197
198
  return { restored: true };
@@ -201,14 +202,22 @@ export class WorkspaceWorkbenchService {
201
202
  (input.repositoryPath !== undefined && typeof input.repositoryPath !== 'string'))
202
203
  throw new Error('GIT_REPOSITORY_INVALID');
203
204
  const workspace = this.gitWorkspace(input.workspaceId);
204
- return resolveGitRepository(workspace.path, input.repositoryPath ?? '');
205
+ return resolveGitRepository(await resolveWorkspaceGitRoot(workspace.path, workspace.includeParentRepository ?? true), input.repositoryPath ?? '');
205
206
  }
206
207
  async fileRepository(workspace, input) {
207
- if (input.worktreePath === undefined)
208
+ if (input.worktreePath === undefined && input.repositoryPath === undefined)
208
209
  return workspace.path;
209
- if (typeof input.worktreePath !== 'string')
210
+ if ((input.worktreePath !== undefined && typeof input.worktreePath !== 'string') ||
211
+ (input.repositoryPath !== undefined && typeof input.repositoryPath !== 'string'))
210
212
  throw new Error('GIT_REPOSITORY_INVALID');
211
- return resolveGitRepositoryTarget(workspace.path, '', input.worktreePath);
213
+ if (typeof input.path !== 'string' ||
214
+ input.path.startsWith('mar-attachment:') ||
215
+ input.previewDirectory !== undefined)
216
+ throw new Error('FILE_PATH_ESCAPE');
217
+ const path = normalizeFilePreviewPath(input.path);
218
+ if (isAbsolute(path) || win32.isAbsolute(path))
219
+ throw new Error('FILE_PATH_ESCAPE');
220
+ return resolveGitRepositoryTarget(await resolveWorkspaceGitRoot(workspace.path, workspace.includeParentRepository ?? true), input.repositoryPath ?? '', input.worktreePath);
212
221
  }
213
222
  refs(input) {
214
223
  if (input.refs === undefined)
@@ -280,6 +289,9 @@ export class WorkspaceWorkbenchService {
280
289
  const input = {
281
290
  workspaceId: workspace.id,
282
291
  path: descriptor.resource.path,
292
+ ...(descriptor.resource.repositoryPath === undefined
293
+ ? {}
294
+ : { repositoryPath: descriptor.resource.repositoryPath }),
283
295
  ...(descriptor.resource.worktreePath === undefined
284
296
  ? {}
285
297
  : { worktreePath: descriptor.resource.worktreePath })
@@ -372,12 +384,12 @@ export class WorkspaceWorkbenchService {
372
384
  typeof input.toRef !== 'string')
373
385
  throw new Error('GIT_DIFF_INVALID');
374
386
  const workspace = this.gitWorkspace(input.workspaceId);
375
- return { diff: await readRestrictedDiff(workspace.path, input.fromRef, input.toRef) };
387
+ return {
388
+ diff: await readRestrictedDiff(await resolveWorkspaceGitRoot(workspace.path, workspace.includeParentRepository ?? true), input.fromRef, input.toRef)
389
+ };
376
390
  }
377
391
  gitWorkspace(workspaceId) {
378
392
  const workspace = this.options.requireWorkspace(workspaceId);
379
- if (workspace.kind !== 'GIT_WORKSPACE')
380
- throw new Error('WORKSPACE_NOT_GIT');
381
393
  return workspace;
382
394
  }
383
395
  }
package/dist/terminal.js CHANGED
@@ -318,17 +318,14 @@ export class TerminalManager {
318
318
  const summary = this.notifySummary(terminal);
319
319
  try {
320
320
  if (terminal.pty !== undefined) {
321
- if (this.platform === 'win32') {
322
- // Killing only the shell bypasses node-pty's native console cleanup.
323
- try {
324
- terminal.pty.kill();
325
- }
326
- catch {
327
- await this.terminate(terminal.pty, this.platform);
328
- }
321
+ // Native PTY hangup reaches POSIX foreground jobs in a separate process group
322
+ // and releases the native console on Windows; shell-group TERM cannot do this.
323
+ try {
324
+ terminal.pty.kill();
329
325
  }
330
- else
326
+ catch {
331
327
  await this.terminate(terminal.pty, this.platform);
328
+ }
332
329
  }
333
330
  if (terminal.pipe !== undefined)
334
331
  await this.terminate(terminal.pipe, this.platform);
@@ -338,13 +335,17 @@ export class TerminalManager {
338
335
  }
339
336
  return summary;
340
337
  }
338
+ /** Ends current terminals without disposing the manager's idle collection. */
339
+ async closeAll() {
340
+ await Promise.all([...this.terminals.values()]
341
+ .filter((terminal) => terminal.state === 'RUNNING')
342
+ .map((terminal) => this.close(terminal.id)));
343
+ }
341
344
  async shutdown() {
342
345
  if (this.idleTimer !== undefined)
343
346
  clearInterval(this.idleTimer);
344
347
  this.idleTimer = undefined;
345
- await Promise.all([...this.terminals.values()]
346
- .filter((terminal) => terminal.state === 'RUNNING')
347
- .map((terminal) => this.close(terminal.id)));
348
+ await this.closeAll();
348
349
  }
349
350
  onFrame(listener) {
350
351
  this.frameListeners.add(listener);
package/dist/workspace.js CHANGED
@@ -1187,7 +1187,7 @@ export function isWithinAllowedRoot(target, roots, platform = hostPlatform()) {
1187
1187
  });
1188
1188
  }
1189
1189
  /** Resolving both candidate and roots rejects Linux symlinks which point outside a root. */
1190
- export async function inspectWorkspace(requestedPath, allowedRoots) {
1190
+ export async function inspectWorkspace(requestedPath, allowedRoots, includeParentRepository = true) {
1191
1191
  const resolvedPath = await realpath(requestedPath);
1192
1192
  const resolvedRoots = await Promise.all(allowedRoots.map((root) => realpath(root)));
1193
1193
  const directory = await stat(resolvedPath);
@@ -1195,16 +1195,40 @@ export async function inspectWorkspace(requestedPath, allowedRoots) {
1195
1195
  throw new Error('WORKSPACE_NOT_ALLOWED');
1196
1196
  }
1197
1197
  try {
1198
- const summary = await readGitSummary(resolvedPath);
1198
+ const repositoryRoot = await resolveWorkspaceGitRoot(resolvedPath, includeParentRepository);
1199
+ const summary = { ...(await readGitSummary(repositoryRoot)), repositoryRoot };
1199
1200
  return { path: resolvedPath, kind: 'GIT_WORKSPACE', gitSummary: summary };
1200
1201
  }
1201
1202
  catch (error) {
1202
- if ((error instanceof GitCommandError && error.code === 128) || isGitUnavailable(error)) {
1203
+ if ((error instanceof GitCommandError && error.code === 128) ||
1204
+ isGitUnavailable(error) ||
1205
+ (error instanceof Error && error.message === 'WORKSPACE_NOT_GIT')) {
1203
1206
  return { path: resolvedPath, kind: 'DIRECTORY' };
1204
1207
  }
1205
1208
  throw error;
1206
1209
  }
1207
1210
  }
1211
+ /** Resolves the working tree without changing the registered Workspace identity. */
1212
+ export async function resolveWorkspaceGitRoot(workspacePath, includeParentRepository = true) {
1213
+ const workspace = await resolveRegisteredWorkspaceRoot(workspacePath);
1214
+ if (!includeParentRepository) {
1215
+ const marker = await lstat(resolve(workspace, '.git')).catch((error) => {
1216
+ if (error.code === 'ENOENT')
1217
+ return undefined;
1218
+ throw error;
1219
+ });
1220
+ if (marker === undefined ||
1221
+ marker.isSymbolicLink() ||
1222
+ (!marker.isFile() && !marker.isDirectory()))
1223
+ throw new Error('WORKSPACE_NOT_GIT');
1224
+ }
1225
+ const result = await runReadOnlyGit(workspace, ['rev-parse', '--show-toplevel']);
1226
+ const root = await realpath(result.text.replace(/\n$/u, ''));
1227
+ if (!includeParentRepository &&
1228
+ normalizeWorkspacePath(root) !== normalizeWorkspacePath(workspace))
1229
+ throw new Error('WORKSPACE_NOT_GIT');
1230
+ return root;
1231
+ }
1208
1232
  export async function readGitSummary(workspacePath) {
1209
1233
  const commonDir = (await runReadOnlyGit(workspacePath, ['rev-parse', '--git-common-dir'])).text.trim();
1210
1234
  const headResult = await runReadOnlyGitAllowFailure(workspacePath, [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@myagentroam/node",
3
- "version": "0.11.0",
3
+ "version": "0.11.2",
4
4
  "description": "MyAgentRoam Node runtime CLI.",
5
5
  "license": "Apache-2.0 AND GPL-2.0-or-later",
6
6
  "type": "module",
@@ -37,10 +37,10 @@
37
37
  "playwright": "1.62.1",
38
38
  "ws": "^8.21.3",
39
39
  "zod": "4.4.3",
40
- "@myagentroam/agent": "0.11.0",
40
+ "@myagentroam/agent": "0.11.2",
41
+ "@myagentroam/protocol": "0.11.2",
41
42
  "@myagentroam/marctl": "0.11.0",
42
- "@myagentroam/code-navigation": "0.11.0",
43
- "@myagentroam/protocol": "0.11.0"
43
+ "@myagentroam/code-navigation": "0.11.0"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@types/ws": "^8.18.1"