@geminixiang/mikan 1.0.0-beta.86 → 1.0.0-beta.87

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 CHANGED
@@ -9,6 +9,12 @@ any release.
9
9
 
10
10
  ## [Unreleased]
11
11
 
12
+ ## [1.0.0-beta.87]
13
+
14
+ ### Fixed
15
+
16
+ - `mikan migrate` moves the per-thread session directories that early versions left inside `sessions/` to the state directory intact, instead of stopping with `Unexpected entry in sessions directory`. Links inside them are moved as links and never followed.
17
+
12
18
  ## [1.0.0-beta.86]
13
19
 
14
20
  ### Breaking
@@ -1 +1 @@
1
- {"version":3,"file":"office-sessions.d.ts","sourceRoot":"","sources":["../../src/migrations/office-sessions.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,SAAS,EAAoB,MAAM,YAAY,CAAC;AA8C9D,eAAO,MAAM,uBAAuB,EAAE,SAcpC,CAAC"}
1
+ {"version":3,"file":"office-sessions.d.ts","sourceRoot":"","sources":["../../src/migrations/office-sessions.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,SAAS,EAAoB,MAAM,YAAY,CAAC;AA0D9D,eAAO,MAAM,uBAAuB,EAAE,SAcpC,CAAC"}
@@ -1,16 +1,27 @@
1
- import { constants as fsConstants, copyFileSync, existsSync, lstatSync, mkdirSync, readdirSync, renameSync, rmdirSync, unlinkSync, } from "node:fs";
1
+ import { constants as fsConstants, copyFileSync, cpSync, existsSync, lstatSync, mkdirSync, readdirSync, renameSync, rmdirSync, rmSync, unlinkSync, } from "node:fs";
2
2
  import { join } from "node:path";
3
3
  import { listRegisteredOffices, officeDir, officeStateDir } from "../office/index.js";
4
4
  const SESSIONS_DIRNAME = "sessions";
5
- function moveFile(source, target) {
5
+ function moveEntry(source, target, isDirectory) {
6
6
  try {
7
7
  renameSync(source, target);
8
8
  }
9
9
  catch (error) {
10
10
  if (!(error instanceof Error && "code" in error && error.code === "EXDEV"))
11
11
  throw error;
12
- copyFileSync(source, target, fsConstants.COPYFILE_EXCL);
13
- unlinkSync(source);
12
+ if (isDirectory) {
13
+ cpSync(source, target, {
14
+ recursive: true,
15
+ verbatimSymlinks: true,
16
+ errorOnExist: true,
17
+ force: false,
18
+ });
19
+ rmSync(source, { recursive: true });
20
+ }
21
+ else {
22
+ copyFileSync(source, target, fsConstants.COPYFILE_EXCL);
23
+ unlinkSync(source);
24
+ }
14
25
  }
15
26
  }
16
27
  function dropLink(context, path) {
@@ -31,7 +42,7 @@ function moveSessions(context, source, target) {
31
42
  }
32
43
  context.report(` sessions ${source} -> ${target}`);
33
44
  const entries = readdirSync(source, { withFileTypes: true });
34
- const unexpected = entries.find((entry) => !entry.isFile() && !entry.isSymbolicLink());
45
+ const unexpected = entries.find((entry) => !entry.isFile() && !entry.isSymbolicLink() && !entry.isDirectory());
35
46
  if (unexpected) {
36
47
  throw new Error(`Unexpected entry in sessions directory: ${join(source, unexpected.name)}`);
37
48
  }
@@ -43,7 +54,7 @@ function moveSessions(context, source, target) {
43
54
  if (entry.isSymbolicLink())
44
55
  dropLink(context, from);
45
56
  else
46
- moveFile(from, join(target, entry.name));
57
+ moveEntry(from, join(target, entry.name), entry.isDirectory());
47
58
  }
48
59
  rmdirSync(source);
49
60
  }
@@ -1 +1 @@
1
- {"version":3,"file":"office-sessions.js","sourceRoot":"","sources":["../../src/migrations/office-sessions.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n constants as fsConstants,\n copyFileSync,\n existsSync,\n lstatSync,\n mkdirSync,\n readdirSync,\n renameSync,\n rmdirSync,\n unlinkSync,\n} from \"node:fs\";\nimport { join } from \"node:path\";\nimport { listRegisteredOffices, officeDir, officeStateDir } from \"../office/index.js\";\nimport type { Migration, MigrationContext } from \"./types.js\";\n\nconst SESSIONS_DIRNAME = \"sessions\";\n\nfunction moveFile(source: string, target: string): void {\n try {\n renameSync(source, target);\n } catch (error) {\n if (!(error instanceof Error && \"code\" in error && error.code === \"EXDEV\")) throw error;\n copyFileSync(source, target, fsConstants.COPYFILE_EXCL);\n unlinkSync(source);\n }\n}\n\nfunction dropLink(context: MigrationContext, path: string): void {\n context.report(` skip link ${path} (removed, never followed)`);\n if (!context.dryRun) unlinkSync(path);\n}\n\nfunction moveSessions(context: MigrationContext, source: string, target: string): void {\n if (lstatSync(source).isSymbolicLink()) {\n dropLink(context, source);\n return;\n }\n if (!lstatSync(source).isDirectory()) {\n throw new Error(`Expected a sessions directory: ${source}`);\n }\n if (existsSync(target) && readdirSync(target).length > 0) {\n throw new Error(`Both ${source} and ${target} exist; merge them into ${target}`);\n }\n context.report(` sessions ${source} -> ${target}`);\n const entries = readdirSync(source, { withFileTypes: true });\n const unexpected = entries.find((entry) => !entry.isFile() && !entry.isSymbolicLink());\n if (unexpected) {\n throw new Error(`Unexpected entry in sessions directory: ${join(source, unexpected.name)}`);\n }\n if (context.dryRun) return;\n mkdirSync(target, { recursive: true, mode: 0o700 });\n for (const entry of entries) {\n const from = join(source, entry.name);\n if (entry.isSymbolicLink()) dropLink(context, from);\n else moveFile(from, join(target, entry.name));\n }\n rmdirSync(source);\n}\n\nexport const officeSessionsMigration: Migration = Object.freeze({\n id: \"0008-office-sessions\",\n summary: \"move session files out of the sandbox-visible office directory\",\n async run(context: MigrationContext): Promise<void> {\n for (const office of listRegisteredOffices(context.stateDir)) {\n const source = join(officeDir(context.workspaceRoot, office), SESSIONS_DIRNAME);\n if (!existsSync(source) && !isLink(source)) continue;\n moveSessions(\n context,\n source,\n join(officeStateDir(context.stateDir, office), SESSIONS_DIRNAME),\n );\n }\n },\n});\n\nfunction isLink(path: string): boolean {\n try {\n return lstatSync(path).isSymbolicLink();\n } catch {\n return false;\n }\n}\n"]}
1
+ {"version":3,"file":"office-sessions.js","sourceRoot":"","sources":["../../src/migrations/office-sessions.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n constants as fsConstants,\n copyFileSync,\n cpSync,\n existsSync,\n lstatSync,\n mkdirSync,\n readdirSync,\n renameSync,\n rmdirSync,\n rmSync,\n unlinkSync,\n} from \"node:fs\";\nimport { join } from \"node:path\";\nimport { listRegisteredOffices, officeDir, officeStateDir } from \"../office/index.js\";\nimport type { Migration, MigrationContext } from \"./types.js\";\n\nconst SESSIONS_DIRNAME = \"sessions\";\n\nfunction moveEntry(source: string, target: string, isDirectory: boolean): void {\n try {\n renameSync(source, target);\n } catch (error) {\n if (!(error instanceof Error && \"code\" in error && error.code === \"EXDEV\")) throw error;\n if (isDirectory) {\n cpSync(source, target, {\n recursive: true,\n verbatimSymlinks: true,\n errorOnExist: true,\n force: false,\n });\n rmSync(source, { recursive: true });\n } else {\n copyFileSync(source, target, fsConstants.COPYFILE_EXCL);\n unlinkSync(source);\n }\n }\n}\n\nfunction dropLink(context: MigrationContext, path: string): void {\n context.report(` skip link ${path} (removed, never followed)`);\n if (!context.dryRun) unlinkSync(path);\n}\n\nfunction moveSessions(context: MigrationContext, source: string, target: string): void {\n if (lstatSync(source).isSymbolicLink()) {\n dropLink(context, source);\n return;\n }\n if (!lstatSync(source).isDirectory()) {\n throw new Error(`Expected a sessions directory: ${source}`);\n }\n if (existsSync(target) && readdirSync(target).length > 0) {\n throw new Error(`Both ${source} and ${target} exist; merge them into ${target}`);\n }\n context.report(` sessions ${source} -> ${target}`);\n const entries = readdirSync(source, { withFileTypes: true });\n const unexpected = entries.find(\n (entry) => !entry.isFile() && !entry.isSymbolicLink() && !entry.isDirectory(),\n );\n if (unexpected) {\n throw new Error(`Unexpected entry in sessions directory: ${join(source, unexpected.name)}`);\n }\n if (context.dryRun) return;\n mkdirSync(target, { recursive: true, mode: 0o700 });\n for (const entry of entries) {\n const from = join(source, entry.name);\n if (entry.isSymbolicLink()) dropLink(context, from);\n else moveEntry(from, join(target, entry.name), entry.isDirectory());\n }\n rmdirSync(source);\n}\n\nexport const officeSessionsMigration: Migration = Object.freeze({\n id: \"0008-office-sessions\",\n summary: \"move session files out of the sandbox-visible office directory\",\n async run(context: MigrationContext): Promise<void> {\n for (const office of listRegisteredOffices(context.stateDir)) {\n const source = join(officeDir(context.workspaceRoot, office), SESSIONS_DIRNAME);\n if (!existsSync(source) && !isLink(source)) continue;\n moveSessions(\n context,\n source,\n join(officeStateDir(context.stateDir, office), SESSIONS_DIRNAME),\n );\n }\n },\n});\n\nfunction isLink(path: string): boolean {\n try {\n return lstatSync(path).isSymbolicLink();\n } catch {\n return false;\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geminixiang/mikan",
3
- "version": "1.0.0-beta.86",
3
+ "version": "1.0.0-beta.87",
4
4
  "description": "Self-hosted AI coding agent for organizations: every Slack channel and DM gets its own sandboxed workspace, credentials, and memory.",
5
5
  "keywords": [
6
6
  "agent",