calendit 1.20260426.1 → 1.20260426.4

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.
@@ -7,9 +7,9 @@ import { writeStdoutLine } from "../core/logger.js";
7
7
  import { logger } from "../core/logger.js";
8
8
  import { ValidationError } from "../core/errors.js";
9
9
  import { t } from "../core/i18n.js";
10
- import { eventkitDoctorJson, eventkitListCalendarsJson, hasEventkitTransport, resolveEventkitHelperPath, } from "../core/eventkitHelper.js";
10
+ import { eventkitDoctorJson, eventkitListCalendarsJson, hasEventkitTransport, resolveBridgeSocketPathForRun, resolveEventkitHelperPath, } from "../core/eventkitHelper.js";
11
11
  import { getDefaultEventkitFetchUrlFromEnv, getFetchedEventkitBridgePath, materializeEventkitBridgeFromNetwork, formatMebibytes, probeHttpArchiveSizeBytes, } from "../core/eventkitBridgeFetch.js";
12
- import { resolveEventkitBridgeAppBundlePath, resolveEventkitBridgeRepoPath, } from "../core/macosBridgeApp.js";
12
+ import { installBuiltBridgeAppToSystemApplications, installBuiltBridgeAppToUserApplications, recordLastOpenedBridgeAppBundle, resolveEventkitBridgeAppBundlePath, resolveEventkitBridgeRepoPath, } from "../core/macosBridgeApp.js";
13
13
  import { loadConfigIfExists } from "./shared.js";
14
14
  import { buildMacosExternalShellLine, buildMacosTerminalSessionLine, openTerminalAndRunShellLine, } from "../core/macosTerminalRelay.js";
15
15
  const execFileAsync = promisify(execFile);
@@ -39,6 +39,47 @@ function isConnectFailure(msg) {
39
39
  function isInteractiveTty() {
40
40
  return Boolean(process.stdin.isTTY && process.stdout.isTTY);
41
41
  }
42
+ /** ビルド済み `.app` を `~/Applications` と `/Applications` にコピー(失敗はログのみ)。`CALENDIT_BRIDGE_BUILD_SKIP_INSTALL=1` で無効化。 */
43
+ async function finalizeBridgeInstallCopies(bridgeRoot) {
44
+ const bundlePath = path.join(bridgeRoot, ".build", "CalenditEventKitBridge.app");
45
+ if (!fs.existsSync(path.join(bundlePath, "Contents", "Info.plist"))) {
46
+ return;
47
+ }
48
+ if (process.env.CALENDIT_BRIDGE_BUILD_SKIP_INSTALL?.trim() === "1") {
49
+ logger.info(t("macos.bridge.buildCopySkipped"));
50
+ return;
51
+ }
52
+ const user = await installBuiltBridgeAppToUserApplications(bundlePath);
53
+ if (user.ok) {
54
+ logger.info(t("macos.bridge.buildCopyUserOk", { path: user.dest }));
55
+ }
56
+ else {
57
+ logger.warn(t("macos.bridge.buildCopyUserWarn", { message: user.message ?? "" }));
58
+ }
59
+ if (process.env.CALENDIT_BRIDGE_BUILD_SKIP_SYSTEM_APP?.trim() === "1") {
60
+ if (user.ok) {
61
+ recordLastOpenedBridgeAppBundle(user.dest);
62
+ }
63
+ else {
64
+ recordLastOpenedBridgeAppBundle(bundlePath);
65
+ }
66
+ return;
67
+ }
68
+ const sys = await installBuiltBridgeAppToSystemApplications(bundlePath);
69
+ if (sys.ok) {
70
+ logger.info(t("macos.bridge.buildCopySystemOk", { path: sys.dest }));
71
+ recordLastOpenedBridgeAppBundle(sys.dest);
72
+ }
73
+ else {
74
+ logger.warn(t("macos.bridge.buildCopySystemSkipped", { message: sys.message ?? "" }));
75
+ if (user.ok) {
76
+ recordLastOpenedBridgeAppBundle(user.dest);
77
+ }
78
+ else {
79
+ recordLastOpenedBridgeAppBundle(bundlePath);
80
+ }
81
+ }
82
+ }
42
83
  /** Run `scripts/build-app-bundle.sh` in `bridgeRoot` and log success. */
43
84
  function runBridgeBuildFromRoot(bridgeRoot) {
44
85
  const script = path.join(bridgeRoot, "scripts/build-app-bundle.sh");
@@ -155,6 +196,7 @@ export function registerMacosCommands(program, deps) {
155
196
  await runBridgeBuildFromRoot(bridgeRoot);
156
197
  const outApp = path.join(bridgeRoot, ".build/CalenditEventKitBridge.app");
157
198
  logger.info(t("macos.bridge.buildOk", { path: outApp }));
199
+ await finalizeBridgeInstallCopies(bridgeRoot);
158
200
  }
159
201
  catch (e) {
160
202
  const message = e instanceof Error ? e.message : String(e);
@@ -181,6 +223,7 @@ export function registerMacosCommands(program, deps) {
181
223
  await runBridgeBuildFromRoot(bridgeRoot);
182
224
  const outApp = path.join(bridgeRoot, ".build/CalenditEventKitBridge.app");
183
225
  logger.info(t("macos.bridge.buildOk", { path: outApp }));
226
+ await finalizeBridgeInstallCopies(bridgeRoot);
184
227
  }
185
228
  catch (e) {
186
229
  const message = e instanceof Error ? e.message : String(e);
@@ -205,6 +248,7 @@ export function registerMacosCommands(program, deps) {
205
248
  }
206
249
  try {
207
250
  await execFileAsync("/usr/bin/open", [p], { shell: false });
251
+ recordLastOpenedBridgeAppBundle(p);
208
252
  logger.info(t("macos.bridge.opened", { path: p }));
209
253
  }
210
254
  catch (e) {
@@ -317,8 +361,19 @@ export function registerMacosCommands(program, deps) {
317
361
  writeStdoutLine("macOS のみ対応です。現在の OS では EventKit ヘルパーを使用できません。");
318
362
  return;
319
363
  }
364
+ const socketPath = resolveBridgeSocketPathForRun();
320
365
  const p = resolveEventkitHelperPath();
321
- writeStdoutLine(`Helper path: ${p ?? "(not found, OK if using bridge only)"}`);
366
+ if (socketPath) {
367
+ writeStdoutLine(`EventKit bridge socket: ${socketPath}`);
368
+ const appPath = resolveEventkitBridgeAppBundlePath();
369
+ if (appPath) {
370
+ writeStdoutLine(t("macos.doctor.bridgeAppResolved", { path: appPath }));
371
+ }
372
+ else {
373
+ writeStdoutLine(t("macos.doctor.bridgeAppUnresolved"));
374
+ }
375
+ }
376
+ writeStdoutLine(`eventkit-helper: ${p ?? (socketPath ? "(not used — doctor uses the bridge above)" : "(not found — build from repo or set CALENDIT_EVENTKIT_HELPER)")}`);
322
377
  if (!hasEventkitTransport()) {
323
378
  writeStdoutLine("EventKit: no helper and no local bridge. Build helper or start CalenditEventKitBridge.app.");
324
379
  return;
@@ -328,7 +383,12 @@ export function registerMacosCommands(program, deps) {
328
383
  writeStdoutLine(JSON.stringify(j, null, 2));
329
384
  if (j.calendarAccess === "denied" && isLikelyIdeIntegratedTerminal()) {
330
385
  writeStdoutLine("");
331
- writeStdoutLine(t("macos.external.suggestionWhenDenied"));
386
+ if (j.transport === "bridge") {
387
+ writeStdoutLine(t("macos.doctor.bridgeDeniedHint"));
388
+ }
389
+ else {
390
+ writeStdoutLine(t("macos.external.suggestionWhenDenied"));
391
+ }
332
392
  }
333
393
  }
334
394
  catch (e) {
@@ -0,0 +1,5 @@
1
+ /**
2
+ * 実行中の `calendit` が属する npm パッケージのルート(`package.json` の `name` が `calendit` のディレクトリ)。
3
+ * `dist/` から親を辿って解決する。フル git クローンでは `native/` がこの下に付く。
4
+ */
5
+ export declare function resolveCalenditPackageRootFromModule(): string | null;
@@ -0,0 +1,31 @@
1
+ import * as fs from "fs";
2
+ import * as path from "path";
3
+ import { fileURLToPath } from "url";
4
+ /**
5
+ * 実行中の `calendit` が属する npm パッケージのルート(`package.json` の `name` が `calendit` のディレクトリ)。
6
+ * `dist/` から親を辿って解決する。フル git クローンでは `native/` がこの下に付く。
7
+ */
8
+ export function resolveCalenditPackageRootFromModule() {
9
+ let dir = path.dirname(fileURLToPath(import.meta.url));
10
+ for (let i = 0; i < 20; i++) {
11
+ const pkg = path.join(dir, "package.json");
12
+ if (fs.existsSync(pkg)) {
13
+ try {
14
+ const raw = fs.readFileSync(pkg, "utf8");
15
+ const j = JSON.parse(raw);
16
+ if (j.name === "calendit") {
17
+ return dir;
18
+ }
19
+ }
20
+ catch {
21
+ // ignore
22
+ }
23
+ }
24
+ const parent = path.dirname(dir);
25
+ if (parent === dir) {
26
+ return null;
27
+ }
28
+ dir = parent;
29
+ }
30
+ return null;
31
+ }
@@ -4,7 +4,7 @@ import { promisify } from "util";
4
4
  import * as fs from "fs";
5
5
  import * as path from "path";
6
6
  import { defaultCalenditDataDir } from "./eventkitHelper.js";
7
- import { resolveCalenditPackageRootFromModule } from "./macosBridgeApp.js";
7
+ import { resolveCalenditPackageRootFromModule } from "./calenditInstallRoot.js";
8
8
  const execFileAsync = promisify(execFile);
9
9
  const fsp = fs.promises;
10
10
  /** Same `CALENDIT_CONFIG_DIR` rules as the bridge: fetched sources live under defaultCalenditDataDir. */
@@ -20,7 +20,7 @@ export declare function resolveBridgeSocketPathForRun(): string | null;
20
20
  export declare function resolveBridgeSocketPath(): string | null;
21
21
  /** true if a helper binary exists, or a bridge socket path is in use (explicit or auto). */
22
22
  export declare function hasEventkitTransport(): boolean;
23
- /** 優先: CALENDIT_EVENTKIT_HELPER → リポジトリ直下の release ビルド */
23
+ /** 優先: CALENDIT_EVENTKIT_HELPER → cwd 配下の release calendit パッケージルート配下(cwd が fetch 先などでもリポジトリ版を拾える) */
24
24
  export declare function resolveEventkitHelperPath(): string | null;
25
25
  /**
26
26
  * Run EventKit helper: **bridge** when a socket is resolved, else spawn `eventkit-helper`.
@@ -3,6 +3,7 @@ import * as fs from "fs";
3
3
  import * as net from "net";
4
4
  import * as os from "os";
5
5
  import * as path from "path";
6
+ import { resolveCalenditPackageRootFromModule } from "./calenditInstallRoot.js";
6
7
  import { t } from "./i18n.js";
7
8
  /** Same directory layout as native/eventkit-bridge (Swift). */
8
9
  export function defaultCalenditDataDir() {
@@ -298,7 +299,7 @@ async function runEventkitHelperSpawn(args, options) {
298
299
  });
299
300
  });
300
301
  }
301
- /** 優先: CALENDIT_EVENTKIT_HELPER → リポジトリ直下の release ビルド */
302
+ /** 優先: CALENDIT_EVENTKIT_HELPER → cwd 配下の release calendit パッケージルート配下(cwd が fetch 先などでもリポジトリ版を拾える) */
302
303
  export function resolveEventkitHelperPath() {
303
304
  const fromEnv = process.env.CALENDIT_EVENTKIT_HELPER?.trim();
304
305
  if (fromEnv && fs.existsSync(fromEnv)) {
@@ -308,6 +309,13 @@ export function resolveEventkitHelperPath() {
308
309
  if (fs.existsSync(rel)) {
309
310
  return rel;
310
311
  }
312
+ const pkgRoot = resolveCalenditPackageRootFromModule();
313
+ if (pkgRoot) {
314
+ const fromPkg = path.join(pkgRoot, "native", "eventkit-helper", ".build", "release", "eventkit-helper");
315
+ if (fs.existsSync(fromPkg)) {
316
+ return fromPkg;
317
+ }
318
+ }
311
319
  return null;
312
320
  }
313
321
  /**
@@ -1,12 +1,24 @@
1
- /**
2
- * Directory of the installed `calendit` npm package (where package.json with name "calendit" lives), or null.
3
- * Used to locate `native/eventkit-bridge` in a full clone; absent from the published npm tarball.
4
- */
5
- export declare function resolveCalenditPackageRootFromModule(): string | null;
1
+ /** Persist which `.app` calendit last opened or installed (helps doctor after cwd / helper path changes). */
2
+ export declare function recordLastOpenedBridgeAppBundle(appPath: string): void;
3
+ export { resolveCalenditPackageRootFromModule } from "./calenditInstallRoot.js";
6
4
  /** `native/eventkit-bridge` with `Package.swift` (source tree), or null. */
7
5
  export declare function resolveEventkitBridgeRepoPath(): string | null;
8
6
  /**
9
- * Resolve the CalenditEventKitBridge .app path for `calendit macos bridge start`.
10
- * Order: CALENDIT_EVENTKIT_BRIDGE_APP, ~/Applications, /Applications, repo .build (dev).
7
+ * Resolve the CalenditEventKitBridge .app path for `calendit macos bridge start` / doctor.
8
+ * Order: `CALENDIT_EVENTKIT_BRIDGE_APP`, then `/Applications` and `~/Applications` (stable TCC targets),
9
+ * then `Package.swift` 隣の `.build/`(fetch / clone / `CALENDIT_EVENTKIT_BRIDGE_ROOT`),
10
+ * then cwd 配下の開発用 `.build/`, finally the path last recorded by `recordLastOpenedBridgeAppBundle` if still present.
11
11
  */
12
12
  export declare function resolveEventkitBridgeAppBundlePath(): string | null;
13
+ /** `~/Applications/CalenditEventKitBridge.app` へ上書きコピー(TCC 用の安定パス向け)。 */
14
+ export declare function installBuiltBridgeAppToUserApplications(sourceApp: string): Promise<{
15
+ ok: boolean;
16
+ dest: string;
17
+ message?: string;
18
+ }>;
19
+ /** `/Applications/CalenditEventKitBridge.app` へ上書きコピー(権限が無い場合は失敗し得る)。 */
20
+ export declare function installBuiltBridgeAppToSystemApplications(sourceApp: string): Promise<{
21
+ ok: boolean;
22
+ dest: string;
23
+ message?: string;
24
+ }>;
@@ -1,39 +1,42 @@
1
1
  import * as fs from "fs";
2
+ import * as fsp from "fs/promises";
2
3
  import * as os from "os";
3
4
  import * as path from "path";
4
- import { fileURLToPath } from "url";
5
+ import { resolveCalenditPackageRootFromModule } from "./calenditInstallRoot.js";
5
6
  import { defaultCalenditDataDir } from "./eventkitHelper.js";
6
7
  function isAppBundle(p) {
7
8
  return p.endsWith(".app") && fs.existsSync(path.join(p, "Contents/Info.plist"));
8
9
  }
9
- /**
10
- * Directory of the installed `calendit` npm package (where package.json with name "calendit" lives), or null.
11
- * Used to locate `native/eventkit-bridge` in a full clone; absent from the published npm tarball.
12
- */
13
- export function resolveCalenditPackageRootFromModule() {
14
- let dir = path.dirname(fileURLToPath(import.meta.url));
15
- for (let i = 0; i < 20; i++) {
16
- const pkg = path.join(dir, "package.json");
17
- if (fs.existsSync(pkg)) {
18
- try {
19
- const raw = fs.readFileSync(pkg, "utf8");
20
- const j = JSON.parse(raw);
21
- if (j.name === "calendit") {
22
- return dir;
23
- }
24
- }
25
- catch {
26
- // ignore
27
- }
28
- }
29
- const parent = path.dirname(dir);
30
- if (parent === dir) {
31
- return null;
10
+ /** Last bundle opened or installed by calendit (fallback when search paths miss). */
11
+ const BRIDGE_BUNDLE_PATH_CACHE = "eventkit-bridge-bundle-path.txt";
12
+ function readCachedBridgeAppBundlePath() {
13
+ const f = path.join(defaultCalenditDataDir(), BRIDGE_BUNDLE_PATH_CACHE);
14
+ try {
15
+ const raw = fs.readFileSync(f, "utf8").trim();
16
+ if (raw && isAppBundle(raw)) {
17
+ return raw;
32
18
  }
33
- dir = parent;
19
+ }
20
+ catch {
21
+ /* missing or unreadable */
34
22
  }
35
23
  return null;
36
24
  }
25
+ /** Persist which `.app` calendit last opened or installed (helps doctor after cwd / helper path changes). */
26
+ export function recordLastOpenedBridgeAppBundle(appPath) {
27
+ const resolved = path.resolve(appPath);
28
+ if (!isAppBundle(resolved)) {
29
+ return;
30
+ }
31
+ try {
32
+ fs.mkdirSync(defaultCalenditDataDir(), { recursive: true });
33
+ fs.writeFileSync(path.join(defaultCalenditDataDir(), BRIDGE_BUNDLE_PATH_CACHE), `${resolved}\n`, "utf8");
34
+ }
35
+ catch {
36
+ /* best-effort */
37
+ }
38
+ }
39
+ export { resolveCalenditPackageRootFromModule } from "./calenditInstallRoot.js";
37
40
  /** `native/eventkit-bridge` with `Package.swift` (source tree), or null. */
38
41
  export function resolveEventkitBridgeRepoPath() {
39
42
  const override = process.env.CALENDIT_EVENTKIT_BRIDGE_ROOT?.trim();
@@ -59,25 +62,59 @@ export function resolveEventkitBridgeRepoPath() {
59
62
  return null;
60
63
  }
61
64
  /**
62
- * Resolve the CalenditEventKitBridge .app path for `calendit macos bridge start`.
63
- * Order: CALENDIT_EVENTKIT_BRIDGE_APP, ~/Applications, /Applications, repo .build (dev).
65
+ * Resolve the CalenditEventKitBridge .app path for `calendit macos bridge start` / doctor.
66
+ * Order: `CALENDIT_EVENTKIT_BRIDGE_APP`, then `/Applications` and `~/Applications` (stable TCC targets),
67
+ * then `Package.swift` 隣の `.build/`(fetch / clone / `CALENDIT_EVENTKIT_BRIDGE_ROOT`),
68
+ * then cwd 配下の開発用 `.build/`, finally the path last recorded by `recordLastOpenedBridgeAppBundle` if still present.
64
69
  */
65
70
  export function resolveEventkitBridgeAppBundlePath() {
66
71
  const fromEnv = process.env.CALENDIT_EVENTKIT_BRIDGE_APP?.trim();
67
72
  if (fromEnv && isAppBundle(fromEnv)) {
68
- return fromEnv;
73
+ return path.resolve(fromEnv);
74
+ }
75
+ const global = "/Applications/CalenditEventKitBridge.app";
76
+ if (isAppBundle(global)) {
77
+ return global;
69
78
  }
70
79
  const homeApps = path.join(os.homedir(), "Applications/CalenditEventKitBridge.app");
71
80
  if (isAppBundle(homeApps)) {
72
81
  return homeApps;
73
82
  }
74
- const global = "/Applications/CalenditEventKitBridge.app";
75
- if (isAppBundle(global)) {
76
- return global;
83
+ const bridgeRoot = resolveEventkitBridgeRepoPath();
84
+ if (bridgeRoot) {
85
+ const fromRepoBuild = path.join(bridgeRoot, ".build", "CalenditEventKitBridge.app");
86
+ if (isAppBundle(fromRepoBuild)) {
87
+ return fromRepoBuild;
88
+ }
77
89
  }
78
90
  const dev = path.join(process.cwd(), "native/eventkit-bridge/.build/CalenditEventKitBridge.app");
79
91
  if (isAppBundle(dev)) {
80
92
  return dev;
81
93
  }
82
- return null;
94
+ return readCachedBridgeAppBundlePath();
95
+ }
96
+ /** `~/Applications/CalenditEventKitBridge.app` へ上書きコピー(TCC 用の安定パス向け)。 */
97
+ export async function installBuiltBridgeAppToUserApplications(sourceApp) {
98
+ const dest = path.join(os.homedir(), "Applications", "CalenditEventKitBridge.app");
99
+ try {
100
+ await fsp.mkdir(path.dirname(dest), { recursive: true });
101
+ await fsp.rm(dest, { recursive: true, force: true });
102
+ await fsp.cp(sourceApp, dest, { recursive: true, force: true });
103
+ return { ok: true, dest };
104
+ }
105
+ catch (e) {
106
+ return { ok: false, dest, message: e instanceof Error ? e.message : String(e) };
107
+ }
108
+ }
109
+ /** `/Applications/CalenditEventKitBridge.app` へ上書きコピー(権限が無い場合は失敗し得る)。 */
110
+ export async function installBuiltBridgeAppToSystemApplications(sourceApp) {
111
+ const dest = "/Applications/CalenditEventKitBridge.app";
112
+ try {
113
+ await fsp.rm(dest, { recursive: true, force: true });
114
+ await fsp.cp(sourceApp, dest, { recursive: true, force: true });
115
+ return { ok: true, dest };
116
+ }
117
+ catch (e) {
118
+ return { ok: false, dest, message: e instanceof Error ? e.message : String(e) };
119
+ }
83
120
  }
@@ -1,3 +1,3 @@
1
1
  /** Generated by scripts/gen-locale-keys.mjs — do not edit by hand */
2
- export type LocaleKey = "common.hint" | "config.check.contexts" | "config.check.contextsNone" | "config.check.fileLine" | "config.check.googleNotSet" | "config.check.googleOk" | "config.check.header" | "config.check.outlookNotSet" | "config.check.outlookOk" | "config.check.uiLocale" | "config.cmd.contextDeleted" | "config.cmd.contextSaved" | "config.cmd.googleSaved" | "config.cmd.localeSet" | "config.cmd.macosTransportSet" | "config.cmd.outlookSaved" | "errors.api.prefix" | "errors.apiWithStatus" | "errors.auth.googleLoginHint" | "errors.auth.prefix" | "errors.config.fileNotFound" | "errors.config.fileNotFoundHint" | "errors.config.invalidFormat" | "errors.config.invalidFormatDetails" | "errors.config.prefix" | "errors.config.readFailed" | "errors.config.readFailedHint" | "errors.context.loadFailed" | "errors.context.loadFailedHint" | "errors.context.missing" | "errors.context.missingHint" | "errors.datetime.invalidFormat" | "errors.datetime.invalidParse" | "errors.datetime.invalidParseHint" | "errors.service.googleCredsNotSet" | "errors.service.googleCredsNotSetHint" | "errors.service.outlookAccountMismatch" | "errors.service.outlookAccountMismatchHint" | "errors.service.outlookCredsNotSet" | "errors.service.outlookCredsNotSetHint" | "errors.service.outlookNoMsalAccounts" | "errors.service.outlookNoMsalAccountsHint" | "errors.unknown" | "errors.validation.prefix" | "eventkit.bridge.bridgeError" | "eventkit.bridge.closedWithoutResponse" | "eventkit.bridge.connectFailed" | "eventkit.bridge.hintStartBridge" | "eventkit.bridge.invalidJson" | "eventkit.bridge.timeout" | "eventkit.bridge.tokenMissing" | "eventkit.helper.exitCode" | "eventkit.helper.hintBuild" | "eventkit.helper.missing" | "eventkit.helper.timeout" | "locale.bootstrap.choiceEn" | "locale.bootstrap.choiceJa" | "locale.bootstrap.prompt" | "macos.bridge.buildFailed" | "macos.bridge.buildNoSource" | "macos.bridge.buildOk" | "macos.bridge.fetchBuildPrompt" | "macos.bridge.fetchCancel" | "macos.bridge.fetchConfirm" | "macos.bridge.fetchFailed" | "macos.bridge.fetchIntro" | "macos.bridge.fetchNoTty" | "macos.bridge.fetchOk" | "macos.bridge.fetchPlan" | "macos.bridge.fetchSizeKnown" | "macos.bridge.fetchSizeUnknown" | "macos.bridge.fetchSkipsExisting" | "macos.bridge.notFound" | "macos.bridge.openFailed" | "macos.bridge.opened" | "macos.external.badSub" | "macos.external.badSubHint" | "macos.external.jsonOnlyForList" | "macos.external.onlyDarwin" | "macos.external.opened" | "macos.external.osascriptFailed" | "macos.external.suggestionWhenDenied" | "macos.setup.canceled" | "macos.setup.contextName" | "macos.setup.contextNameRequired" | "macos.setup.noCalendars" | "macos.setup.noTransport" | "macos.setup.notDarwin" | "macos.setup.pickCalendar" | "macos.setup.saved" | "macos.setup.startBridgePrompt" | "macos.setup.tcc";
2
+ export type LocaleKey = "common.hint" | "config.check.contexts" | "config.check.contextsNone" | "config.check.fileLine" | "config.check.googleNotSet" | "config.check.googleOk" | "config.check.header" | "config.check.outlookNotSet" | "config.check.outlookOk" | "config.check.uiLocale" | "config.cmd.contextDeleted" | "config.cmd.contextSaved" | "config.cmd.googleSaved" | "config.cmd.localeSet" | "config.cmd.macosTransportSet" | "config.cmd.outlookSaved" | "errors.api.prefix" | "errors.apiWithStatus" | "errors.auth.googleLoginHint" | "errors.auth.prefix" | "errors.config.fileNotFound" | "errors.config.fileNotFoundHint" | "errors.config.invalidFormat" | "errors.config.invalidFormatDetails" | "errors.config.prefix" | "errors.config.readFailed" | "errors.config.readFailedHint" | "errors.context.loadFailed" | "errors.context.loadFailedHint" | "errors.context.missing" | "errors.context.missingHint" | "errors.datetime.invalidFormat" | "errors.datetime.invalidParse" | "errors.datetime.invalidParseHint" | "errors.service.googleCredsNotSet" | "errors.service.googleCredsNotSetHint" | "errors.service.outlookAccountMismatch" | "errors.service.outlookAccountMismatchHint" | "errors.service.outlookCredsNotSet" | "errors.service.outlookCredsNotSetHint" | "errors.service.outlookNoMsalAccounts" | "errors.service.outlookNoMsalAccountsHint" | "errors.unknown" | "errors.validation.prefix" | "eventkit.bridge.bridgeError" | "eventkit.bridge.closedWithoutResponse" | "eventkit.bridge.connectFailed" | "eventkit.bridge.hintStartBridge" | "eventkit.bridge.invalidJson" | "eventkit.bridge.timeout" | "eventkit.bridge.tokenMissing" | "eventkit.helper.exitCode" | "eventkit.helper.hintBuild" | "eventkit.helper.missing" | "eventkit.helper.timeout" | "locale.bootstrap.choiceEn" | "locale.bootstrap.choiceJa" | "locale.bootstrap.prompt" | "macos.bridge.buildCopySkipped" | "macos.bridge.buildCopySystemOk" | "macos.bridge.buildCopySystemSkipped" | "macos.bridge.buildCopyUserOk" | "macos.bridge.buildCopyUserWarn" | "macos.bridge.buildFailed" | "macos.bridge.buildNoSource" | "macos.bridge.buildOk" | "macos.bridge.fetchBuildPrompt" | "macos.bridge.fetchCancel" | "macos.bridge.fetchConfirm" | "macos.bridge.fetchFailed" | "macos.bridge.fetchIntro" | "macos.bridge.fetchNoTty" | "macos.bridge.fetchOk" | "macos.bridge.fetchPlan" | "macos.bridge.fetchSizeKnown" | "macos.bridge.fetchSizeUnknown" | "macos.bridge.fetchSkipsExisting" | "macos.bridge.notFound" | "macos.bridge.openFailed" | "macos.bridge.opened" | "macos.doctor.bridgeAppResolved" | "macos.doctor.bridgeAppUnresolved" | "macos.doctor.bridgeDeniedHint" | "macos.external.badSub" | "macos.external.badSubHint" | "macos.external.jsonOnlyForList" | "macos.external.onlyDarwin" | "macos.external.opened" | "macos.external.osascriptFailed" | "macos.external.suggestionWhenDenied" | "macos.setup.canceled" | "macos.setup.contextName" | "macos.setup.contextNameRequired" | "macos.setup.noCalendars" | "macos.setup.noTransport" | "macos.setup.notDarwin" | "macos.setup.pickCalendar" | "macos.setup.saved" | "macos.setup.startBridgePrompt" | "macos.setup.tcc";
3
3
  export declare const LOCALE_KEYS: readonly LocaleKey[];
@@ -57,6 +57,11 @@ export const LOCALE_KEYS = [
57
57
  "locale.bootstrap.choiceEn",
58
58
  "locale.bootstrap.choiceJa",
59
59
  "locale.bootstrap.prompt",
60
+ "macos.bridge.buildCopySkipped",
61
+ "macos.bridge.buildCopySystemOk",
62
+ "macos.bridge.buildCopySystemSkipped",
63
+ "macos.bridge.buildCopyUserOk",
64
+ "macos.bridge.buildCopyUserWarn",
60
65
  "macos.bridge.buildFailed",
61
66
  "macos.bridge.buildNoSource",
62
67
  "macos.bridge.buildOk",
@@ -74,6 +79,9 @@ export const LOCALE_KEYS = [
74
79
  "macos.bridge.notFound",
75
80
  "macos.bridge.openFailed",
76
81
  "macos.bridge.opened",
82
+ "macos.doctor.bridgeAppResolved",
83
+ "macos.doctor.bridgeAppUnresolved",
84
+ "macos.doctor.bridgeDeniedHint",
77
85
  "macos.external.badSub",
78
86
  "macos.external.badSubHint",
79
87
  "macos.external.jsonOnlyForList",
@@ -91,9 +91,14 @@
91
91
  "bridge": {
92
92
  "openFailed": "Could not open the bridge app: {message}.",
93
93
  "opened": "Launched {path}. Wait a few seconds, then run: calendit macos doctor",
94
- "notFound": "CalenditEventKitBridge.app not found. Install a release, use Homebrew when available, or in a full clone run: calendit macos bridge build then: calendit macos bridge start",
94
+ "notFound": "CalenditEventKitBridge.app not found. After `calendit macos bridge fetch` + `bridge build`, `.build` under the bridge root and ~/Applications are searched automatically. Otherwise install a release, use Homebrew when available, or run `bridge build` then `macos bridge start`.",
95
95
  "buildNoSource": "EventKit bridge sources are not available next to this install. Use a full git clone, or set CALENDIT_EVENTKIT_BRIDGE_ROOT to your native/eventkit-bridge directory.",
96
96
  "buildOk": "Build finished. App bundle: {path}",
97
+ "buildCopySkipped": "Skipping post-build copy to Applications (CALENDIT_BRIDGE_BUILD_SKIP_INSTALL=1).",
98
+ "buildCopyUserOk": "Copied bridge .app to {path} (usable from `calendit macos bridge start`).",
99
+ "buildCopyUserWarn": "Could not copy to ~/Applications: {message}",
100
+ "buildCopySystemOk": "Copied bridge .app to {path}",
101
+ "buildCopySystemSkipped": "Skipped copy to /Applications ({message}). Copy manually or use sudo if you need it there.",
97
102
  "buildFailed": "EventKit bridge build failed: {message}",
98
103
  "fetchIntro": "Download the calendit repository snapshot from GitHub, extract only native/eventkit-bridge, and place it under your calendit data directory (next to the bridge token when using the default location). A Swift build (see next step) will compile CalenditEventKitBridge.app.",
99
104
  "fetchPlan": "• Source archive: {url}\n• Approx. download size: {sizeLine}\n• Extract to: {dest}\n• Then (optional) run the Swift build to create the .app under .build/ in that folder.",
@@ -119,6 +124,11 @@
119
124
  "startBridgePrompt": "The bridge does not seem to be running. Open CalenditEventKitBridge.app now?",
120
125
  "canceled": "Setup canceled."
121
126
  },
127
+ "doctor": {
128
+ "bridgeDeniedHint": "Using the bridge, but calendar access is denied. Check System Settings → Privacy & Security → Calendars and grant **CalenditEventKitBridge** full access (TCC applies to the .app, not this terminal).",
129
+ "bridgeAppResolved": "CalenditEventKitBridge.app (same resolution as `macos bridge start`): {path}",
130
+ "bridgeAppUnresolved": "CalenditEventKitBridge.app: could not resolve a bundle path (run `macos bridge build` / `bridge start`, or set CALENDIT_EVENTKIT_BRIDGE_APP)."
131
+ },
122
132
  "external": {
123
133
  "onlyDarwin": "macOS only.",
124
134
  "badSub": "Subcommand must be `doctor`, `list-calendars`, or `shell`.",
@@ -91,9 +91,14 @@
91
91
  "bridge": {
92
92
  "openFailed": "ブリッジ app を起動できません: {message}",
93
93
  "opened": "起動しました: {path}。数秒待ってから: calendit macos doctor",
94
- "notFound": "CalenditEventKitBridge.app が見つかりません。配布 / Homebrew を使うか、完全なクローン上で: calendit macos bridge build 次に: calendit macos bridge start",
94
+ "notFound": "CalenditEventKitBridge.app が見つかりません。`calendit macos bridge fetch` + `bridge build` 後は `.build` ~/Applications を自動検出します。未ビルドなら配布 / Homebrew、またはクローンで `bridge build` のうえ `macos bridge start` を。",
95
95
  "buildNoSource": "EventKit ブリッジのソースがこのインストール近くにありません。git クローン一式を使うか、CALENDIT_EVENTKIT_BRIDGE_ROOT に native/eventkit-bridge を指定するか、**calendit macos bridge fetch** で取得できます。",
96
96
  "buildOk": "ビルドが完了しました。{path}",
97
+ "buildCopySkipped": "環境変数により、ビルド後の Applications へのコピーをスキップしました。",
98
+ "buildCopyUserOk": "ブリッジ .app をコピーしました: {path}(`calendit macos bridge start` から利用できます)。",
99
+ "buildCopyUserWarn": "~/Applications へのコピーに失敗しました: {message}",
100
+ "buildCopySystemOk": "ブリッジ .app をコピーしました: {path}",
101
+ "buildCopySystemSkipped": "/Applications へのコピーをスキップしました(権限など: {message})。必要なら手動でコピーするか、`sudo` で同パスへ配置してください。",
97
102
  "buildFailed": "EventKit ブリッジのビルドに失敗しました: {message}",
98
103
  "fetchIntro": "GitHub 上の calendit リポジトリのスナップショットを取り、**native/eventkit-bridge だけ**を、既定の calendit データ領域(通常は `~/Library/Application Support/calendit/` 配下)に展開します。次のステップで Swift により CalenditEventKitBridge.app をビルドします。",
99
104
  "fetchPlan": "• 取得元: {url}\n• おおよそのダウンロード量: {sizeLine}\n• 展開先: {dest}\n• その後(任意)同フォルダで Swift ビルドを実行し、`.build/CalenditEventKitBridge.app` を作ります。",
@@ -119,6 +124,11 @@
119
124
  "startBridgePrompt": "ブリッジが起動していない可能性があります。CalenditEventKitBridge.app を開きますか?",
120
125
  "canceled": "セットアップを中止しました。"
121
126
  },
127
+ "doctor": {
128
+ "bridgeDeniedHint": "ブリッジ経由ですがカレンダーが拒否されています。システム設定 → プライバシーとセキュリティ → カレンダー で **CalenditEventKitBridge** のフルアクセスを確認してください(このターミナルではなく .app 側の許可です)。",
129
+ "bridgeAppResolved": "CalenditEventKitBridge.app(`macos bridge start` と同じ候補解決): {path}",
130
+ "bridgeAppUnresolved": "CalenditEventKitBridge.app: 候補を解決できませんでした(`macos bridge build` / `bridge start`、または CALENDIT_EVENTKIT_BRIDGE_APP を設定してください)。"
131
+ },
122
132
  "external": {
123
133
  "onlyDarwin": "macOS のみ対応です。",
124
134
  "badSub": "サブコマンドは `doctor` / `list-calendars` / `shell` です。",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "calendit",
3
- "version": "1.20260426.1",
3
+ "version": "1.20260426.4",
4
4
  "description": "Terminal-based calendar management tool for Google Calendar, Outlook, and macOS Calendar (EventKit) via CLI",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",