calendit 1.0.2 → 1.20260425.6
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/README.md +65 -62
- package/dist/commands/accounts.d.ts +4 -0
- package/dist/commands/accounts.js +26 -0
- package/dist/commands/add.js +8 -0
- package/dist/commands/apply.js +16 -2
- package/dist/commands/auth.js +11 -2
- package/dist/commands/config.js +50 -16
- package/dist/commands/macos.d.ts +3 -0
- package/dist/commands/macos.js +401 -0
- package/dist/commands/onboard.d.ts +2 -0
- package/dist/commands/onboard.js +79 -0
- package/dist/commands/query.js +4 -24
- package/dist/commands/shared.d.ts +3 -2
- package/dist/commands/shared.js +21 -5
- package/dist/core/accountStatus.d.ts +18 -0
- package/dist/core/accountStatus.js +74 -0
- package/dist/core/applier.js +4 -26
- package/dist/core/auth.js +7 -11
- package/dist/core/authStatus.d.ts +20 -0
- package/dist/core/authStatus.js +82 -0
- package/dist/core/config.d.ts +11 -1
- package/dist/core/config.js +73 -6
- package/dist/core/datetime.js +3 -2
- package/dist/core/errors.d.ts +3 -0
- package/dist/core/errors.js +5 -0
- package/dist/core/eventkitBridgeFetch.d.ts +26 -0
- package/dist/core/eventkitBridgeFetch.js +159 -0
- package/dist/core/eventkitEnvFromConfig.d.ts +7 -0
- package/dist/core/eventkitEnvFromConfig.js +24 -0
- package/dist/core/eventkitHelper.d.ts +50 -0
- package/dist/core/eventkitHelper.js +336 -0
- package/dist/core/formatter.d.ts +41 -0
- package/dist/core/formatter.js +79 -0
- package/dist/core/i18n.d.ts +7 -0
- package/dist/core/i18n.js +52 -0
- package/dist/core/localeBootstrap.d.ts +12 -0
- package/dist/core/localeBootstrap.js +74 -0
- package/dist/core/logger.d.ts +2 -0
- package/dist/core/logger.js +5 -0
- package/dist/core/macosBridgeApp.d.ts +12 -0
- package/dist/core/macosBridgeApp.js +83 -0
- package/dist/core/macosTerminalRelay.d.ts +12 -0
- package/dist/core/macosTerminalRelay.js +62 -0
- package/dist/core/outlookCalendarList.d.ts +15 -0
- package/dist/core/outlookCalendarList.js +27 -0
- package/dist/core/timeRangeForQuery.d.ts +39 -0
- package/dist/core/timeRangeForQuery.js +78 -0
- package/dist/generated/locale-keys.d.ts +3 -0
- package/dist/generated/locale-keys.js +90 -0
- package/dist/index.js +103 -18
- package/dist/locales/en.json +128 -0
- package/dist/locales/ja.json +128 -0
- package/dist/services/google.d.ts +1 -0
- package/dist/services/google.js +9 -4
- package/dist/services/macos.d.ts +14 -0
- package/dist/services/macos.js +115 -0
- package/dist/services/outlook.d.ts +5 -0
- package/dist/services/outlook.js +30 -10
- package/dist/test_runner.js +11 -2
- package/dist/types/index.d.ts +12 -1
- package/package.json +16 -5
package/README.md
CHANGED
|
@@ -1,94 +1,97 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
|
+
<h1>🗓️ calendit</h1>
|
|
3
|
+
<p><b>ターミナルから Google / Outlook / Mac のカレンダーを自在に操るCLIツール</b></p>
|
|
4
|
+
|
|
5
|
+
[](https://opensource.org/licenses/ISC)
|
|
6
|
+
[](https://www.typescriptlang.org/)
|
|
7
|
+
[](https://nodejs.org/)
|
|
8
|
+
[](https://www.npmjs.com/package/calendit)
|
|
9
|
+
</div>
|
|
2
10
|
|
|
3
|
-
|
|
4
|
-
人間のための Markdown 管理と、AI エージェントのための JSON 管理を両立します。
|
|
11
|
+
<br>
|
|
5
12
|
|
|
6
|
-
|
|
7
|
-
|
|
13
|
+
> **calendit (カレンディット)** は、黒い画面(ターミナル)から、あなたのカレンダーの予定を調べたり、追加したり、Markdownなどのファイルと同期するためのコマンドラインツールです。
|
|
14
|
+
> 人間にとっても、AIエージェントにとっても、使いやすく設計されています。
|
|
8
15
|
|
|
9
|
-
##
|
|
16
|
+
## ✨ 何ができるの?(主な機能)
|
|
10
17
|
|
|
11
|
-
- **Markdown
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
- **macOS 最適化**: 永続的なトークン管理とローカル時刻の完全サポート。
|
|
18
|
+
- 🔍 **予定の確認**: 指定した期間の予定を **Markdown**, **CSV**, **JSON** 形式でスッと表示できます。
|
|
19
|
+
- 📝 **予定の一括反映**: テキストファイルに書いた予定を、そのままカレンダーにまとめて登録・更新できます。
|
|
20
|
+
- ⚡️ **サクッと追加**: `--summary "ランチ" --start "12:00"` のように1行で予定を追加できます。
|
|
21
|
+
- 🔄 **アカウント切り替え**: 仕事用のGoogle、個人のOutlook、このMac専用のカレンダーなどを、名前(コンテキスト)で簡単に使い分けられます。
|
|
22
|
+
- 🛡️ **安全設計**: 間違えてカレンダーを消さないよう、変更前の確認や `--dry-run`(テスト実行)が用意されています。
|
|
17
23
|
|
|
18
|
-
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## 🧍 初めての方・一般ユーザー向け
|
|
27
|
+
|
|
28
|
+
プログラムの知識がなくても大丈夫です。以下の**3ステップ**で使い始められます!
|
|
19
29
|
|
|
20
30
|
### 1. インストール
|
|
31
|
+
Node.js (バージョン18以上) が入っているパソコンのターミナルで、次のコマンドを実行するだけです。
|
|
21
32
|
|
|
22
33
|
```bash
|
|
23
|
-
|
|
24
|
-
cd calendit
|
|
25
|
-
npm install
|
|
26
|
-
npm run build
|
|
27
|
-
# パスを通す(任意)
|
|
28
|
-
npm link
|
|
34
|
+
npm install -g calendit
|
|
29
35
|
```
|
|
30
36
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
各サービスのセットアップガイドに従って、API 認証情報を設定します。
|
|
37
|
+
> [!TIP]
|
|
38
|
+
> インストールができたら `calendit --version` で動作を確認してみましょう。
|
|
34
39
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
```bash
|
|
39
|
-
# Google の設定例
|
|
40
|
-
calendit config set-google --id YOUR_CLIENT_ID --secret YOUR_CLIENT_SECRET
|
|
41
|
-
calendit auth login google
|
|
42
|
-
|
|
43
|
-
# Outlook の設定例
|
|
44
|
-
calendit config set-outlook --id YOUR_CLIENT_ID
|
|
45
|
-
calendit auth login outlook
|
|
46
|
-
```
|
|
40
|
+
### 2. 初期設定(使い方ガイド)
|
|
41
|
+
インストールが終わったら、どのカレンダーと繋ぐかを設定します。
|
|
42
|
+
図解付きで分かりやすく解説した**初心者向けガイド**をご用意しました。こちらを見ながら進めてください!
|
|
47
43
|
|
|
48
|
-
|
|
44
|
+
👉 **[初心者向けガイド(日本語)を読む](docs/beginner-guide-ja.md)**
|
|
49
45
|
|
|
50
|
-
|
|
46
|
+
---
|
|
51
47
|
|
|
52
|
-
|
|
53
|
-
# 仕事用カレンダーの登録
|
|
54
|
-
calendit config set-context work --service google --calendar primary
|
|
55
|
-
```
|
|
48
|
+
## 🤖 AI・エージェント向け(Cursor / GitHub Copilot 等)
|
|
56
49
|
|
|
57
|
-
|
|
50
|
+
AIエージェント(LLM)が自律的にカレンダーを操作する能力を持たせたい場合は、以下のドキュメントを参照してください。
|
|
58
51
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
52
|
+
- **[AI・エージェント向け 初回オンボーディングラリー](docs/ai-onboarding-rally.md)**
|
|
53
|
+
- エージェントが最初に読み込むべき「対話用プレイブック」です。
|
|
54
|
+
- **[AIエージェント向けリファレンス](docs/for-ai-agents.md)**
|
|
55
|
+
- リポジトリの構成、環境変数、テストの仕組み、OAuthの注意点など、機械可読な構造化情報を提供しています。
|
|
62
56
|
|
|
63
|
-
|
|
64
|
-
# --dry-run で変更内容を事前に確認できます
|
|
65
|
-
calendit apply --in today.md --dry-run
|
|
57
|
+
---
|
|
66
58
|
|
|
67
|
-
|
|
68
|
-
calendit add --summary "ランチミーティング" --start "today 12:00" --set work
|
|
69
|
-
```
|
|
59
|
+
## 💻 開発者向け
|
|
70
60
|
|
|
71
|
-
|
|
61
|
+
本リポジトリのソースコードを利用して、自分でビルドしたり開発に参加したりする場合はこちら。
|
|
72
62
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
- [Outlook カレンダー セットアップガイド](docs/setup_outlook.md)
|
|
76
|
-
- [開発者向けガイド (テスト・設計)](docs/development.md)
|
|
63
|
+
<details>
|
|
64
|
+
<summary><b>開発環境のセットアップ(クリックして展開)</b></summary>
|
|
77
65
|
|
|
78
|
-
|
|
66
|
+
Node.js 18以上とGitが必要です。
|
|
79
67
|
|
|
80
|
-
|
|
68
|
+
```bash
|
|
69
|
+
git clone https://github.com/chromatribe/calendit.git
|
|
70
|
+
cd calendit
|
|
71
|
+
npm ci
|
|
72
|
+
npm run build
|
|
73
|
+
npm run ux:link
|
|
74
|
+
calendit --version
|
|
75
|
+
```
|
|
76
|
+
> 以降のより詳細な手順は [getting-started.md](docs/getting-started.md) に集約しています。
|
|
81
77
|
|
|
78
|
+
### 自動テスト
|
|
82
79
|
```bash
|
|
83
80
|
npm test
|
|
84
81
|
```
|
|
82
|
+
</details>
|
|
83
|
+
|
|
84
|
+
---
|
|
85
85
|
|
|
86
|
-
|
|
86
|
+
## 📚 ドキュメント一覧
|
|
87
87
|
|
|
88
|
-
|
|
88
|
+
使い方やトラブルシューティングなど、すべてのドキュメントは `docs/` フォルダにあります。
|
|
89
|
+
目的に合わせてお読みください。
|
|
89
90
|
|
|
90
|
-
|
|
91
|
+
👉 **[ドキュメント目次 (docs/README.md)](docs/README.md)**
|
|
91
92
|
|
|
92
|
-
|
|
93
|
+
---
|
|
93
94
|
|
|
94
|
-
|
|
95
|
+
<div align="center">
|
|
96
|
+
<small>ライセンス: ISC | 作者: chromatribe - s.ohara (ivis.klain@chromatri.be)</small>
|
|
97
|
+
</div>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { loadConfigIfExists } from "./shared.js";
|
|
2
|
+
import { writeStdoutLine } from "../core/logger.js";
|
|
3
|
+
import { buildAccountStatusRows, formatAccountStatusTable } from "../core/accountStatus.js";
|
|
4
|
+
export async function printAccountStatusTable(deps) {
|
|
5
|
+
await loadConfigIfExists(deps.config);
|
|
6
|
+
const contexts = deps.config.getAllContexts();
|
|
7
|
+
const names = Object.keys(contexts);
|
|
8
|
+
if (names.length === 0) {
|
|
9
|
+
writeStdoutLine("コンテキストが定義されていません。`calendit config set-context` で追加してください。");
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
const rows = await buildAccountStatusRows(contexts, {
|
|
13
|
+
auth: deps.auth,
|
|
14
|
+
outlookCreds: deps.config.getOutlookCreds(),
|
|
15
|
+
});
|
|
16
|
+
writeStdoutLine(formatAccountStatusTable(rows));
|
|
17
|
+
}
|
|
18
|
+
export function registerAccountsCommands(program, deps) {
|
|
19
|
+
const accountsCmd = program.command("accounts").description("Calendar accounts and connection status (all services)");
|
|
20
|
+
accountsCmd
|
|
21
|
+
.command("status")
|
|
22
|
+
.description("Show each context's service, calendar, account, and connection state (google / outlook / macos)")
|
|
23
|
+
.action(async () => {
|
|
24
|
+
await printAccountStatusTable(deps);
|
|
25
|
+
});
|
|
26
|
+
}
|
package/dist/commands/add.js
CHANGED
|
@@ -12,6 +12,7 @@ export function registerAddCommand(program, deps) {
|
|
|
12
12
|
.option("--end <dateTime>", "End date/time")
|
|
13
13
|
.option("--location <text>", "Event location")
|
|
14
14
|
.option("--description <text>", "Event description")
|
|
15
|
+
.option("--attendees <emails>", "Comma-separated attendee emails (macOS EventKit: may be ignored depending on OS)")
|
|
15
16
|
.option("--set <name>", "Use a named context")
|
|
16
17
|
.option("--calendar <id>", "Explicit Calendar ID")
|
|
17
18
|
.option("--dry-run", "Preview addition without applying", false)
|
|
@@ -32,6 +33,12 @@ export function registerAddCommand(program, deps) {
|
|
|
32
33
|
}
|
|
33
34
|
const formattedStart = formatInTimeZone(startDate, timeZone, "yyyy-MM-dd'T'HH:mm:ssXXX");
|
|
34
35
|
const formattedEnd = formatInTimeZone(endDate, timeZone, "yyyy-MM-dd'T'HH:mm:ssXXX");
|
|
36
|
+
const attendeeList = options.attendees
|
|
37
|
+
? options.attendees
|
|
38
|
+
.split(",")
|
|
39
|
+
.map((s) => s.trim())
|
|
40
|
+
.filter(Boolean)
|
|
41
|
+
: undefined;
|
|
35
42
|
logger.info(`Adding event: ${options.summary}`);
|
|
36
43
|
logger.info(`Start: ${formattedStart}`);
|
|
37
44
|
logger.info(`End: ${formattedEnd}`);
|
|
@@ -45,6 +52,7 @@ export function registerAddCommand(program, deps) {
|
|
|
45
52
|
end: formattedEnd,
|
|
46
53
|
location: options.location,
|
|
47
54
|
description: options.description,
|
|
55
|
+
...(attendeeList?.length ? { attendees: attendeeList } : {}),
|
|
48
56
|
});
|
|
49
57
|
logger.info(`✅ Event added successfully: "${options.summary}"`);
|
|
50
58
|
});
|
package/dist/commands/apply.js
CHANGED
|
@@ -4,6 +4,7 @@ import { Applier } from "../core/applier.js";
|
|
|
4
4
|
import { getServiceForContext } from "./shared.js";
|
|
5
5
|
import { ValidationError } from "../core/errors.js";
|
|
6
6
|
import { logger } from "../core/logger.js";
|
|
7
|
+
import { computeInputAutoRange, mergeApplySyncRanges, parseOptionalTimeRangeForApply, } from "../core/timeRangeForQuery.js";
|
|
7
8
|
const COLOR_RESET = "\x1b[0m";
|
|
8
9
|
const COLOR_GREEN = "\x1b[32m";
|
|
9
10
|
const COLOR_BLUE = "\x1b[34m";
|
|
@@ -17,6 +18,8 @@ export function registerApplyCommand(program, deps) {
|
|
|
17
18
|
.option("--calendar <id>", "Explicit Calendar ID")
|
|
18
19
|
.option("--sync", "Delete events not in the file", false)
|
|
19
20
|
.option("--dry-run", "Preview changes without applying", false)
|
|
21
|
+
.option("--start <iso>", "Optional: widen fetch range (same as query: YYYY-MM-DD, 7d, today, etc.). Use with --end to include events outside the file's dates (e.g. for moves).")
|
|
22
|
+
.option("--end <iso>", "Optional: end of fetch range. Required when using --start unless start is a relative range (e.g. 7d).")
|
|
20
23
|
.action(async (options) => {
|
|
21
24
|
if (!options.in) {
|
|
22
25
|
throw new ValidationError("Input file required.", "Use --in <file> to specify input.");
|
|
@@ -33,14 +36,25 @@ export function registerApplyCommand(program, deps) {
|
|
|
33
36
|
inputEvents = Formatter.fromCsv(inputData);
|
|
34
37
|
}
|
|
35
38
|
else {
|
|
36
|
-
|
|
39
|
+
const parsed = Formatter.fromJson(inputData);
|
|
40
|
+
if (parsed.warnings.length > 0) {
|
|
41
|
+
parsed.warnings.forEach((w) => logger.warn(w));
|
|
42
|
+
}
|
|
43
|
+
inputEvents = parsed.events;
|
|
37
44
|
}
|
|
38
45
|
const applier = new Applier(service);
|
|
46
|
+
const now = new Date();
|
|
47
|
+
const autoR = computeInputAutoRange(inputEvents);
|
|
48
|
+
const cliR = parseOptionalTimeRangeForApply(options.start, options.end, now);
|
|
49
|
+
const range = mergeApplySyncRanges(autoR, cliR);
|
|
50
|
+
if (range) {
|
|
51
|
+
logger.info(`Sync range: ${range.start.toISOString()} to ${range.end.toISOString()}`);
|
|
52
|
+
}
|
|
39
53
|
if (options.dryRun) {
|
|
40
54
|
logger.info("[DRY RUN - 実際の変更は行いません]");
|
|
41
55
|
}
|
|
42
56
|
logger.info(`Applying changes to ${calendarId}...`);
|
|
43
|
-
const results = await applier.apply(calendarId, inputEvents,
|
|
57
|
+
const results = await applier.apply(calendarId, inputEvents, range, {
|
|
44
58
|
dryRun: options.dryRun,
|
|
45
59
|
sync: options.sync,
|
|
46
60
|
});
|
package/dist/commands/auth.js
CHANGED
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
import { loadConfigIfExists } from "./shared.js";
|
|
2
2
|
import { ConfigError, ValidationError } from "../core/errors.js";
|
|
3
3
|
import { logger } from "../core/logger.js";
|
|
4
|
+
import { t } from "../core/i18n.js";
|
|
5
|
+
import { printAccountStatusTable } from "./accounts.js";
|
|
4
6
|
export function registerAuthCommands(program, deps) {
|
|
5
7
|
const authCmd = program.command("auth").description("Authentication management");
|
|
8
|
+
authCmd
|
|
9
|
+
.command("status")
|
|
10
|
+
.description("Same as `calendit accounts status` (deprecated name; use accounts status for clarity)")
|
|
11
|
+
.action(async () => {
|
|
12
|
+
logger.info("推奨: 全サービス横断の状態は `calendit accounts status` を使用してください。");
|
|
13
|
+
await printAccountStatusTable(deps);
|
|
14
|
+
});
|
|
6
15
|
authCmd
|
|
7
16
|
.command("login <service>")
|
|
8
17
|
.description("Login to Google or Outlook")
|
|
@@ -14,7 +23,7 @@ export function registerAuthCommands(program, deps) {
|
|
|
14
23
|
if (service === "google") {
|
|
15
24
|
const creds = deps.config.getGoogleCreds();
|
|
16
25
|
if (!creds) {
|
|
17
|
-
throw new ConfigError("
|
|
26
|
+
throw new ConfigError(t("errors.service.googleCredsNotSet"), t("errors.auth.googleLoginHint"));
|
|
18
27
|
}
|
|
19
28
|
logger.info("Google 認証フローを開始します...");
|
|
20
29
|
await deps.auth.loginGoogle(creds.id, creds.secret, accountId);
|
|
@@ -24,7 +33,7 @@ export function registerAuthCommands(program, deps) {
|
|
|
24
33
|
if (service === "outlook") {
|
|
25
34
|
const creds = deps.config.getOutlookCreds();
|
|
26
35
|
if (!creds) {
|
|
27
|
-
throw new ConfigError("
|
|
36
|
+
throw new ConfigError(t("errors.service.outlookCredsNotSet"), t("errors.service.outlookCredsNotSetHint"));
|
|
28
37
|
}
|
|
29
38
|
logger.info("Outlook 認証フローを開始します...");
|
|
30
39
|
await deps.auth.loginOutlook(creds.id, creds.tenantId, accountId);
|
package/dist/commands/config.js
CHANGED
|
@@ -2,8 +2,22 @@ import * as fs from "fs/promises";
|
|
|
2
2
|
import { loadConfigIfExists } from "./shared.js";
|
|
3
3
|
import { ValidationError } from "../core/errors.js";
|
|
4
4
|
import { logger } from "../core/logger.js";
|
|
5
|
+
import { isUiLocale, t } from "../core/i18n.js";
|
|
5
6
|
export function registerConfigCommands(program, deps) {
|
|
6
7
|
const configCmd = program.command("config").description("Configuration management");
|
|
8
|
+
configCmd
|
|
9
|
+
.command("set-locale <code>")
|
|
10
|
+
.description("Set UI language (en or ja) and persist to config")
|
|
11
|
+
.action(async (code) => {
|
|
12
|
+
await loadConfigIfExists(deps.config);
|
|
13
|
+
const c = code.trim().toLowerCase();
|
|
14
|
+
if (!isUiLocale(c)) {
|
|
15
|
+
throw new ValidationError(`Invalid locale: ${code}`, "Use en or ja.");
|
|
16
|
+
}
|
|
17
|
+
deps.config.setUi({ locale: c, localePromptCompleted: true });
|
|
18
|
+
await deps.config.save();
|
|
19
|
+
logger.info(t("config.cmd.localeSet", { locale: c }));
|
|
20
|
+
});
|
|
7
21
|
configCmd
|
|
8
22
|
.command("set-google")
|
|
9
23
|
.description("Set Google API credentials (manually or via JSON file)")
|
|
@@ -35,7 +49,7 @@ export function registerConfigCommands(program, deps) {
|
|
|
35
49
|
}
|
|
36
50
|
deps.config.setGoogleCreds(id, secret);
|
|
37
51
|
await deps.config.save();
|
|
38
|
-
logger.info("
|
|
52
|
+
logger.info(t("config.cmd.googleSaved"));
|
|
39
53
|
});
|
|
40
54
|
configCmd
|
|
41
55
|
.command("set-outlook")
|
|
@@ -46,7 +60,7 @@ export function registerConfigCommands(program, deps) {
|
|
|
46
60
|
await loadConfigIfExists(deps.config);
|
|
47
61
|
deps.config.setOutlookCreds(options.id, options.tenant);
|
|
48
62
|
await deps.config.save();
|
|
49
|
-
logger.info("
|
|
63
|
+
logger.info(t("config.cmd.outlookSaved"));
|
|
50
64
|
});
|
|
51
65
|
configCmd
|
|
52
66
|
.command("check")
|
|
@@ -58,13 +72,33 @@ export function registerConfigCommands(program, deps) {
|
|
|
58
72
|
const contexts = deps.config.getAllContexts();
|
|
59
73
|
const contextEntries = Object.entries(contexts);
|
|
60
74
|
const mask = (value) => (value.length <= 8 ? value : `${value.slice(0, 3)}...${value.slice(-3)}`);
|
|
61
|
-
logger.info("
|
|
62
|
-
logger.info(
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
75
|
+
logger.info(t("config.check.header"));
|
|
76
|
+
logger.info(googleCreds
|
|
77
|
+
? t("config.check.googleOk", { mask: mask(googleCreds.id) })
|
|
78
|
+
: t("config.check.googleNotSet"));
|
|
79
|
+
logger.info(outlookCreds
|
|
80
|
+
? t("config.check.outlookOk", { mask: mask(outlookCreds.id) })
|
|
81
|
+
: t("config.check.outlookNotSet"));
|
|
82
|
+
logger.info(contextEntries.length > 0
|
|
83
|
+
? t("config.check.contexts", {
|
|
84
|
+
list: contextEntries.map(([name, ctx]) => `${name} (${ctx.service}/${ctx.calendarId})`).join(", "),
|
|
85
|
+
})
|
|
86
|
+
: t("config.check.contextsNone"));
|
|
87
|
+
logger.info(t("config.check.fileLine"));
|
|
88
|
+
logger.info(t("config.check.uiLocale", { locale: deps.config.getUi()?.locale ?? "en" }));
|
|
89
|
+
});
|
|
90
|
+
configCmd
|
|
91
|
+
.command("set-macos-transport <value>")
|
|
92
|
+
.description("Persist default EventKit transport: auto, bridge, or helper (used when CALENDIT_EVENTKIT_BRIDGE is unset in the shell)")
|
|
93
|
+
.action(async (value) => {
|
|
94
|
+
await loadConfigIfExists(deps.config);
|
|
95
|
+
const v = value.trim().toLowerCase();
|
|
96
|
+
if (v !== "auto" && v !== "bridge" && v !== "helper") {
|
|
97
|
+
throw new ValidationError("Value must be auto, bridge, or helper.");
|
|
98
|
+
}
|
|
99
|
+
deps.config.setEventkitDefaultTransport(v);
|
|
100
|
+
await deps.config.save();
|
|
101
|
+
logger.info(t("config.cmd.macosTransportSet", { value: v }));
|
|
68
102
|
});
|
|
69
103
|
configCmd
|
|
70
104
|
.command("delete-context <name>")
|
|
@@ -73,21 +107,21 @@ export function registerConfigCommands(program, deps) {
|
|
|
73
107
|
await loadConfigIfExists(deps.config);
|
|
74
108
|
const deleted = deps.config.deleteContext(name);
|
|
75
109
|
if (!deleted) {
|
|
76
|
-
throw new ValidationError(
|
|
110
|
+
throw new ValidationError(t("errors.context.missing", { name }), t("errors.context.missingHint", { name }));
|
|
77
111
|
}
|
|
78
112
|
await deps.config.save();
|
|
79
|
-
logger.info(
|
|
113
|
+
logger.info(t("config.cmd.contextDeleted", { name }));
|
|
80
114
|
});
|
|
81
115
|
configCmd
|
|
82
116
|
.command("set-context <name>")
|
|
83
117
|
.description("Set a named context (e.g. work, hobby)")
|
|
84
|
-
.requiredOption("--service <service>", "google or
|
|
85
|
-
.requiredOption("--calendar <id>", "Calendar ID")
|
|
118
|
+
.requiredOption("--service <service>", "google, outlook, or macos")
|
|
119
|
+
.requiredOption("--calendar <id>", "Calendar ID (for macos: EventKit calendarIdentifier from `calendit macos list-calendars`)")
|
|
86
120
|
.option("--account <id>", "Custom account identifier for tokens")
|
|
87
121
|
.action(async (name, options) => {
|
|
88
122
|
await loadConfigIfExists(deps.config);
|
|
89
|
-
if (options.service !== "google" && options.service !== "outlook") {
|
|
90
|
-
throw new ValidationError("Service must be 'google' or '
|
|
123
|
+
if (options.service !== "google" && options.service !== "outlook" && options.service !== "macos") {
|
|
124
|
+
throw new ValidationError("Service must be 'google', 'outlook', or 'macos'.");
|
|
91
125
|
}
|
|
92
126
|
deps.config.setContext(name, {
|
|
93
127
|
service: options.service,
|
|
@@ -95,6 +129,6 @@ export function registerConfigCommands(program, deps) {
|
|
|
95
129
|
accountId: options.account,
|
|
96
130
|
});
|
|
97
131
|
await deps.config.save();
|
|
98
|
-
logger.info(
|
|
132
|
+
logger.info(t("config.cmd.contextSaved", { name }));
|
|
99
133
|
});
|
|
100
134
|
}
|