calendit 1.20260425.6 → 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.
- package/dist/commands/macos.js +64 -4
- package/dist/commands/shared.js +12 -5
- package/dist/core/authStatus.d.ts +1 -1
- package/dist/core/authStatus.js +6 -3
- package/dist/core/calenditInstallRoot.d.ts +5 -0
- package/dist/core/calenditInstallRoot.js +31 -0
- package/dist/core/eventkitBridgeFetch.js +1 -1
- package/dist/core/eventkitHelper.d.ts +1 -1
- package/dist/core/eventkitHelper.js +9 -1
- package/dist/core/macosBridgeApp.d.ts +19 -7
- package/dist/core/macosBridgeApp.js +69 -32
- package/dist/core/outlookAccountMatch.d.ts +10 -0
- package/dist/core/outlookAccountMatch.js +30 -0
- package/dist/generated/locale-keys.d.ts +1 -1
- package/dist/generated/locale-keys.js +12 -0
- package/dist/locales/en.json +16 -2
- package/dist/locales/ja.json +16 -2
- package/dist/services/outlook.js +15 -4
- package/package.json +2 -2
package/dist/commands/macos.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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) {
|
package/dist/commands/shared.js
CHANGED
|
@@ -2,8 +2,9 @@ import { GoogleCalendarService } from "../services/google.js";
|
|
|
2
2
|
import { OutlookCalendarService } from "../services/outlook.js";
|
|
3
3
|
import { MockCalendarService } from "../services/mock.js";
|
|
4
4
|
import { MacosCalendarService } from "../services/macos.js";
|
|
5
|
-
import { ConfigError } from "../core/errors.js";
|
|
5
|
+
import { AuthError, ConfigError } from "../core/errors.js";
|
|
6
6
|
import { t } from "../core/i18n.js";
|
|
7
|
+
import { formatOutlookCacheUsernames, pickOutlookMsalAccount } from "../core/outlookAccountMatch.js";
|
|
7
8
|
export async function loadConfigIfExists(config) {
|
|
8
9
|
try {
|
|
9
10
|
await config.load();
|
|
@@ -73,10 +74,16 @@ export async function getServiceForContext(deps, contextName) {
|
|
|
73
74
|
}
|
|
74
75
|
const pca = await auth.getOutlookClient(creds.id, creds.tenantId);
|
|
75
76
|
const accounts = await pca.getTokenCache().getAllAccounts();
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
77
|
+
if (accounts.length === 0) {
|
|
78
|
+
throw new AuthError(t("errors.service.outlookNoMsalAccounts"), t("errors.service.outlookNoMsalAccountsHint"));
|
|
79
|
+
}
|
|
80
|
+
const account = pickOutlookMsalAccount(accounts, ctx.accountId);
|
|
81
|
+
if (!account) {
|
|
82
|
+
throw new AuthError(t("errors.service.outlookAccountMismatch", {
|
|
83
|
+
expected: ctx.accountId.trim(),
|
|
84
|
+
cached: formatOutlookCacheUsernames(accounts),
|
|
85
|
+
}), t("errors.service.outlookAccountMismatchHint", { expected: ctx.accountId.trim() }));
|
|
86
|
+
}
|
|
80
87
|
return {
|
|
81
88
|
service: new OutlookCalendarService(pca, account),
|
|
82
89
|
calendarId: ctx.calendarId,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ContextConfig } from "../types/index.js";
|
|
2
2
|
import type { OutlookCredentials } from "../types/index.js";
|
|
3
3
|
import type { AuthManager } from "./auth.js";
|
|
4
|
-
export type AuthTokenColumn = "OK" | "NOT LOGGED IN" | "EXPIRED" | "NOT CONFIGURED";
|
|
4
|
+
export type AuthTokenColumn = "OK" | "NOT LOGGED IN" | "EXPIRED" | "NOT CONFIGURED" | "ACCOUNT MISMATCH";
|
|
5
5
|
export interface AuthStatusRow {
|
|
6
6
|
context: string;
|
|
7
7
|
service: string;
|
package/dist/core/authStatus.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as fs from "fs/promises";
|
|
2
2
|
import { getGoogleTokenFilePath } from "./config.js";
|
|
3
|
+
import { pickOutlookMsalAccount } from "./outlookAccountMatch.js";
|
|
3
4
|
/** `getServiceForContext` と同じトークンキー */
|
|
4
5
|
export function googleTokenKeyForContext(contextName, ctx) {
|
|
5
6
|
return contextName || ctx.accountId;
|
|
@@ -30,11 +31,13 @@ export async function evaluateOutlookToken(auth, creds, ctx) {
|
|
|
30
31
|
if (accounts.length === 0) {
|
|
31
32
|
return "NOT LOGGED IN";
|
|
32
33
|
}
|
|
33
|
-
if (!ctx.accountId) {
|
|
34
|
+
if (!ctx.accountId?.trim()) {
|
|
34
35
|
return "OK";
|
|
35
36
|
}
|
|
36
|
-
const
|
|
37
|
-
|
|
37
|
+
const picked = pickOutlookMsalAccount(accounts, ctx.accountId);
|
|
38
|
+
if (picked)
|
|
39
|
+
return "OK";
|
|
40
|
+
return "ACCOUNT MISMATCH";
|
|
38
41
|
}
|
|
39
42
|
export function buildAuthStatusRows(contexts, deps) {
|
|
40
43
|
const entries = Object.entries(contexts).sort(([a], [b]) => a.localeCompare(b));
|
|
@@ -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 "./
|
|
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 →
|
|
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 →
|
|
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
|
-
|
|
3
|
-
|
|
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
|
|
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 {
|
|
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
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
75
|
-
if (
|
|
76
|
-
|
|
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
|
|
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
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { AccountInfo } from "@azure/msal-node";
|
|
2
|
+
/**
|
|
3
|
+
* MSAL キャッシュ上のアカウントが、コンテキストの `accountId`(メールまたは homeAccountId)に対応するか。
|
|
4
|
+
*/
|
|
5
|
+
export declare function outlookAccountMatchesConfig(account: AccountInfo, configAccountId: string): boolean;
|
|
6
|
+
/**
|
|
7
|
+
* `accountId` 未指定のときは先頭アカウント。指定時は一致するもののみ(フォールバックしない)。
|
|
8
|
+
*/
|
|
9
|
+
export declare function pickOutlookMsalAccount(accounts: AccountInfo[], accountId: string | undefined): AccountInfo | undefined;
|
|
10
|
+
export declare function formatOutlookCacheUsernames(accounts: AccountInfo[]): string;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
function norm(s) {
|
|
2
|
+
return s.trim().toLowerCase();
|
|
3
|
+
}
|
|
4
|
+
/**
|
|
5
|
+
* MSAL キャッシュ上のアカウントが、コンテキストの `accountId`(メールまたは homeAccountId)に対応するか。
|
|
6
|
+
*/
|
|
7
|
+
export function outlookAccountMatchesConfig(account, configAccountId) {
|
|
8
|
+
const want = norm(configAccountId);
|
|
9
|
+
if (!want)
|
|
10
|
+
return false;
|
|
11
|
+
if (norm(account.username) === want)
|
|
12
|
+
return true;
|
|
13
|
+
if (account.homeAccountId && norm(account.homeAccountId) === want)
|
|
14
|
+
return true;
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* `accountId` 未指定のときは先頭アカウント。指定時は一致するもののみ(フォールバックしない)。
|
|
19
|
+
*/
|
|
20
|
+
export function pickOutlookMsalAccount(accounts, accountId) {
|
|
21
|
+
if (accounts.length === 0)
|
|
22
|
+
return undefined;
|
|
23
|
+
const id = accountId?.trim();
|
|
24
|
+
if (!id)
|
|
25
|
+
return accounts[0];
|
|
26
|
+
return accounts.find((a) => outlookAccountMatchesConfig(a, id));
|
|
27
|
+
}
|
|
28
|
+
export function formatOutlookCacheUsernames(accounts) {
|
|
29
|
+
return accounts.map((a) => a.username || a.homeAccountId || "(unknown)").join(", ");
|
|
30
|
+
}
|
|
@@ -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.outlookCredsNotSet" | "errors.service.outlookCredsNotSetHint" | "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[];
|
|
@@ -35,8 +35,12 @@ export const LOCALE_KEYS = [
|
|
|
35
35
|
"errors.datetime.invalidParseHint",
|
|
36
36
|
"errors.service.googleCredsNotSet",
|
|
37
37
|
"errors.service.googleCredsNotSetHint",
|
|
38
|
+
"errors.service.outlookAccountMismatch",
|
|
39
|
+
"errors.service.outlookAccountMismatchHint",
|
|
38
40
|
"errors.service.outlookCredsNotSet",
|
|
39
41
|
"errors.service.outlookCredsNotSetHint",
|
|
42
|
+
"errors.service.outlookNoMsalAccounts",
|
|
43
|
+
"errors.service.outlookNoMsalAccountsHint",
|
|
40
44
|
"errors.unknown",
|
|
41
45
|
"errors.validation.prefix",
|
|
42
46
|
"eventkit.bridge.bridgeError",
|
|
@@ -53,6 +57,11 @@ export const LOCALE_KEYS = [
|
|
|
53
57
|
"locale.bootstrap.choiceEn",
|
|
54
58
|
"locale.bootstrap.choiceJa",
|
|
55
59
|
"locale.bootstrap.prompt",
|
|
60
|
+
"macos.bridge.buildCopySkipped",
|
|
61
|
+
"macos.bridge.buildCopySystemOk",
|
|
62
|
+
"macos.bridge.buildCopySystemSkipped",
|
|
63
|
+
"macos.bridge.buildCopyUserOk",
|
|
64
|
+
"macos.bridge.buildCopyUserWarn",
|
|
56
65
|
"macos.bridge.buildFailed",
|
|
57
66
|
"macos.bridge.buildNoSource",
|
|
58
67
|
"macos.bridge.buildOk",
|
|
@@ -70,6 +79,9 @@ export const LOCALE_KEYS = [
|
|
|
70
79
|
"macos.bridge.notFound",
|
|
71
80
|
"macos.bridge.openFailed",
|
|
72
81
|
"macos.bridge.opened",
|
|
82
|
+
"macos.doctor.bridgeAppResolved",
|
|
83
|
+
"macos.doctor.bridgeAppUnresolved",
|
|
84
|
+
"macos.doctor.bridgeDeniedHint",
|
|
73
85
|
"macos.external.badSub",
|
|
74
86
|
"macos.external.badSubHint",
|
|
75
87
|
"macos.external.jsonOnlyForList",
|
package/dist/locales/en.json
CHANGED
|
@@ -26,7 +26,11 @@
|
|
|
26
26
|
"googleCredsNotSet": "Google credentials are not set.",
|
|
27
27
|
"googleCredsNotSetHint": "Run `calendit config set-google --id <id> --secret <secret>`.",
|
|
28
28
|
"outlookCredsNotSet": "Outlook credentials are not set.",
|
|
29
|
-
"outlookCredsNotSetHint": "Run `calendit config set-outlook --id <id>`."
|
|
29
|
+
"outlookCredsNotSetHint": "Run `calendit config set-outlook --id <id>`.",
|
|
30
|
+
"outlookNoMsalAccounts": "No Outlook sign-in found in the MSAL cache.",
|
|
31
|
+
"outlookNoMsalAccountsHint": "Run `calendit auth login outlook --set <context>`.",
|
|
32
|
+
"outlookAccountMismatch": "No cached Outlook account matches context accountId \"{expected}\". Cached usernames: {cached}",
|
|
33
|
+
"outlookAccountMismatchHint": "In the browser sign-in UI, choose \"{expected}\" and run `calendit auth login outlook --set <context>` again. You may have signed in with a different Microsoft account."
|
|
30
34
|
},
|
|
31
35
|
"context": {
|
|
32
36
|
"missing": "Context '{name}' was not found.",
|
|
@@ -87,9 +91,14 @@
|
|
|
87
91
|
"bridge": {
|
|
88
92
|
"openFailed": "Could not open the bridge app: {message}.",
|
|
89
93
|
"opened": "Launched {path}. Wait a few seconds, then run: calendit macos doctor",
|
|
90
|
-
"notFound": "CalenditEventKitBridge.app not found.
|
|
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`.",
|
|
91
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.",
|
|
92
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.",
|
|
93
102
|
"buildFailed": "EventKit bridge build failed: {message}",
|
|
94
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.",
|
|
95
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.",
|
|
@@ -115,6 +124,11 @@
|
|
|
115
124
|
"startBridgePrompt": "The bridge does not seem to be running. Open CalenditEventKitBridge.app now?",
|
|
116
125
|
"canceled": "Setup canceled."
|
|
117
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
|
+
},
|
|
118
132
|
"external": {
|
|
119
133
|
"onlyDarwin": "macOS only.",
|
|
120
134
|
"badSub": "Subcommand must be `doctor`, `list-calendars`, or `shell`.",
|
package/dist/locales/ja.json
CHANGED
|
@@ -26,7 +26,11 @@
|
|
|
26
26
|
"googleCredsNotSet": "Google の認証情報が未設定です。",
|
|
27
27
|
"googleCredsNotSetHint": "`calendit config set-google --id <id> --secret <secret>` を実行してください。",
|
|
28
28
|
"outlookCredsNotSet": "Outlook の認証情報が未設定です。",
|
|
29
|
-
"outlookCredsNotSetHint": "`calendit config set-outlook --id <id>` を先に実行してください。"
|
|
29
|
+
"outlookCredsNotSetHint": "`calendit config set-outlook --id <id>` を先に実行してください。",
|
|
30
|
+
"outlookNoMsalAccounts": "Outlook 用のサインイン情報が MSAL キャッシュにありません。",
|
|
31
|
+
"outlookNoMsalAccountsHint": "`calendit auth login outlook --set <コンテキスト名>` を実行してください。",
|
|
32
|
+
"outlookAccountMismatch": "コンテキストの accountId「{expected}」に一致する Outlook アカウントがキャッシュにありません。現在キャッシュされているユーザー名: {cached}",
|
|
33
|
+
"outlookAccountMismatchHint": "ブラウザのサインイン画面で「{expected}」を選び直して `calendit auth login outlook --set <コンテキスト名>` を再実行してください。別の Microsoft アカウントでログインしている可能性があります。"
|
|
30
34
|
},
|
|
31
35
|
"context": {
|
|
32
36
|
"missing": "コンテキスト '{name}' が見つかりません。",
|
|
@@ -87,9 +91,14 @@
|
|
|
87
91
|
"bridge": {
|
|
88
92
|
"openFailed": "ブリッジ app を起動できません: {message}",
|
|
89
93
|
"opened": "起動しました: {path}。数秒待ってから: calendit macos doctor",
|
|
90
|
-
"notFound": "CalenditEventKitBridge.app
|
|
94
|
+
"notFound": "CalenditEventKitBridge.app が見つかりません。`calendit macos bridge fetch` + `bridge build` 後は `.build` や ~/Applications を自動検出します。未ビルドなら配布 / Homebrew、またはクローンで `bridge build` のうえ `macos bridge start` を。",
|
|
91
95
|
"buildNoSource": "EventKit ブリッジのソースがこのインストール近くにありません。git クローン一式を使うか、CALENDIT_EVENTKIT_BRIDGE_ROOT に native/eventkit-bridge を指定するか、**calendit macos bridge fetch** で取得できます。",
|
|
92
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` で同パスへ配置してください。",
|
|
93
102
|
"buildFailed": "EventKit ブリッジのビルドに失敗しました: {message}",
|
|
94
103
|
"fetchIntro": "GitHub 上の calendit リポジトリのスナップショットを取り、**native/eventkit-bridge だけ**を、既定の calendit データ領域(通常は `~/Library/Application Support/calendit/` 配下)に展開します。次のステップで Swift により CalenditEventKitBridge.app をビルドします。",
|
|
95
104
|
"fetchPlan": "• 取得元: {url}\n• おおよそのダウンロード量: {sizeLine}\n• 展開先: {dest}\n• その後(任意)同フォルダで Swift ビルドを実行し、`.build/CalenditEventKitBridge.app` を作ります。",
|
|
@@ -115,6 +124,11 @@
|
|
|
115
124
|
"startBridgePrompt": "ブリッジが起動していない可能性があります。CalenditEventKitBridge.app を開きますか?",
|
|
116
125
|
"canceled": "セットアップを中止しました。"
|
|
117
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
|
+
},
|
|
118
132
|
"external": {
|
|
119
133
|
"onlyDarwin": "macOS のみ対応です。",
|
|
120
134
|
"badSub": "サブコマンドは `doctor` / `list-calendars` / `shell` です。",
|
package/dist/services/outlook.js
CHANGED
|
@@ -2,6 +2,11 @@ import { AbstractCalendarService } from "./base.js";
|
|
|
2
2
|
import { ApiError, AuthError } from "../core/errors.js";
|
|
3
3
|
import { logger } from "../core/logger.js";
|
|
4
4
|
import { graphCalendarItemToCalendarInfo, mergeOutlookCalendarsFirstWins } from "../core/outlookCalendarList.js";
|
|
5
|
+
const CALENDAR_LIST_PAGE_SIZE = 100;
|
|
6
|
+
function withListTop(path) {
|
|
7
|
+
const sep = path.includes("?") ? "&" : "?";
|
|
8
|
+
return `${path}${sep}$top=${CALENDAR_LIST_PAGE_SIZE}`;
|
|
9
|
+
}
|
|
5
10
|
export class OutlookCalendarService extends AbstractCalendarService {
|
|
6
11
|
pca;
|
|
7
12
|
account;
|
|
@@ -83,15 +88,21 @@ export class OutlookCalendarService extends AbstractCalendarService {
|
|
|
83
88
|
}
|
|
84
89
|
async listCalendars() {
|
|
85
90
|
const layers = [];
|
|
86
|
-
const topLevel = await this.requestPaginatedList("/me/calendars");
|
|
91
|
+
const topLevel = await this.requestPaginatedList(withListTop("/me/calendars"));
|
|
87
92
|
layers.push(topLevel.map((item) => graphCalendarItemToCalendarInfo(item)));
|
|
88
|
-
const groups = await this.requestPaginatedList("/me/calendarGroups");
|
|
93
|
+
const groups = await this.requestPaginatedList(withListTop("/me/calendarGroups"));
|
|
89
94
|
for (const group of groups) {
|
|
90
95
|
const groupId = group.id;
|
|
91
|
-
const inGroup = await this.requestPaginatedList(`/me/calendarGroups/${encodeURIComponent(groupId)}/calendars`);
|
|
96
|
+
const inGroup = await this.requestPaginatedList(withListTop(`/me/calendarGroups/${encodeURIComponent(groupId)}/calendars`));
|
|
92
97
|
layers.push(inGroup.map((item) => graphCalendarItemToCalendarInfo(item)));
|
|
93
98
|
}
|
|
94
|
-
|
|
99
|
+
const merged = mergeOutlookCalendarsFirstWins(layers);
|
|
100
|
+
logger.debug("Outlook listCalendars merged", {
|
|
101
|
+
layerSizes: layers.map((l) => l.length),
|
|
102
|
+
mergedCount: merged.length,
|
|
103
|
+
names: merged.map((c) => c.name),
|
|
104
|
+
});
|
|
105
|
+
return merged;
|
|
95
106
|
}
|
|
96
107
|
async createCalendar(name) {
|
|
97
108
|
const data = await this.request("/me/calendars", {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "calendit",
|
|
3
|
-
"version": "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",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"gen:locales": "node scripts/gen-locale-keys.mjs",
|
|
20
20
|
"check:locales": "node scripts/check-locale-parity.mjs",
|
|
21
21
|
"build": "npm run gen:locales && tsc && node scripts/copy-locales.mjs",
|
|
22
|
-
"test": "npm run build && node --test tests/unit/outlook-calendar-merge.test.mjs && node --loader ts-node/esm src/test_runner.ts",
|
|
22
|
+
"test": "npm run build && node --test tests/unit/outlook-calendar-merge.test.mjs tests/unit/outlook-account-match.test.mjs && node --loader ts-node/esm src/test_runner.ts",
|
|
23
23
|
"prepack": "npm test",
|
|
24
24
|
"pack:check": "npm pack --dry-run",
|
|
25
25
|
"ux:link": "npm run build && npm link"
|