@simplysm/sd-claude 13.0.69 → 13.0.71

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.
Files changed (78) hide show
  1. package/README.md +12 -601
  2. package/claude/agents/sd-api-reviewer.md +0 -1
  3. package/claude/agents/sd-code-reviewer.md +0 -1
  4. package/claude/agents/sd-code-simplifier.md +1 -1
  5. package/claude/agents/sd-security-reviewer.md +0 -1
  6. package/claude/refs/sd-angular.md +26 -26
  7. package/claude/refs/sd-orm-v12.md +17 -17
  8. package/claude/rules/sd-refs-linker.md +14 -14
  9. package/claude/sd-statusline.js +21 -21
  10. package/claude/skills/sd-api-name-review/SKILL.md +1 -2
  11. package/claude/skills/sd-brainstorm/SKILL.md +3 -4
  12. package/claude/skills/sd-check/SKILL.md +1 -2
  13. package/claude/skills/sd-commit/SKILL.md +2 -3
  14. package/claude/skills/sd-debug/SKILL.md +1 -2
  15. package/claude/skills/sd-discuss/SKILL.md +1 -3
  16. package/claude/skills/sd-document/SKILL.md +99 -0
  17. package/claude/skills/sd-document/extract_docx.py +92 -0
  18. package/claude/skills/sd-document/extract_pdf.py +102 -0
  19. package/claude/skills/sd-document/extract_pptx.py +77 -0
  20. package/claude/skills/sd-document/extract_xlsx.py +83 -0
  21. package/claude/skills/sd-email-analyze/SKILL.md +6 -6
  22. package/claude/skills/sd-plan/SKILL.md +1 -3
  23. package/claude/skills/sd-plan-dev/SKILL.md +94 -111
  24. package/claude/skills/sd-plan-dev/code-quality-reviewer-prompt.md +1 -1
  25. package/claude/skills/sd-plan-dev/final-review-prompt.md +1 -1
  26. package/claude/skills/sd-plan-dev/spec-reviewer-prompt.md +1 -1
  27. package/claude/skills/sd-readme/SKILL.md +107 -88
  28. package/claude/skills/sd-review/SKILL.md +14 -16
  29. package/claude/skills/sd-skill/SKILL.md +6 -317
  30. package/claude/skills/sd-skill/cso-guide.md +161 -0
  31. package/claude/skills/sd-skill/writing-guide.md +163 -0
  32. package/claude/skills/sd-tdd/SKILL.md +1 -3
  33. package/claude/skills/sd-use/SKILL.md +1 -3
  34. package/claude/skills/sd-worktree/SKILL.md +52 -2
  35. package/dist/commands/auth-add.d.ts +2 -0
  36. package/dist/commands/auth-add.d.ts.map +1 -0
  37. package/dist/commands/auth-add.js +32 -0
  38. package/dist/commands/auth-add.js.map +6 -0
  39. package/dist/commands/auth-list.d.ts +2 -0
  40. package/dist/commands/auth-list.d.ts.map +1 -0
  41. package/dist/commands/auth-list.js +37 -0
  42. package/dist/commands/auth-list.js.map +6 -0
  43. package/dist/commands/auth-remove.d.ts +2 -0
  44. package/dist/commands/auth-remove.d.ts.map +1 -0
  45. package/dist/commands/auth-remove.js +22 -0
  46. package/dist/commands/auth-remove.js.map +6 -0
  47. package/dist/commands/auth-use.d.ts +2 -0
  48. package/dist/commands/auth-use.d.ts.map +1 -0
  49. package/dist/commands/auth-use.js +33 -0
  50. package/dist/commands/auth-use.js.map +6 -0
  51. package/dist/commands/auth-utils.d.ts +11 -0
  52. package/dist/commands/auth-utils.d.ts.map +1 -0
  53. package/dist/commands/auth-utils.js +57 -0
  54. package/dist/commands/auth-utils.js.map +6 -0
  55. package/dist/commands/install.js +3 -3
  56. package/dist/commands/install.js.map +1 -1
  57. package/dist/index.d.ts +5 -0
  58. package/dist/index.d.ts.map +1 -1
  59. package/dist/index.js +5 -0
  60. package/dist/index.js.map +1 -1
  61. package/dist/sd-claude.js +68 -3
  62. package/dist/sd-claude.js.map +1 -1
  63. package/package.json +3 -2
  64. package/scripts/sync-claude-assets.mjs +1 -1
  65. package/src/commands/auth-add.ts +36 -0
  66. package/src/commands/auth-list.ts +44 -0
  67. package/src/commands/auth-remove.ts +26 -0
  68. package/src/commands/auth-use.ts +53 -0
  69. package/src/commands/auth-utils.ts +65 -0
  70. package/src/commands/install.ts +19 -19
  71. package/src/index.ts +5 -0
  72. package/src/sd-claude.ts +81 -3
  73. package/tests/auth-add.spec.ts +74 -0
  74. package/tests/auth-list.spec.ts +175 -0
  75. package/tests/auth-remove.spec.ts +74 -0
  76. package/tests/auth-use.spec.ts +153 -0
  77. package/tests/auth-utils.spec.ts +173 -0
  78. package/claude/skills/sd-explore/SKILL.md +0 -78
@@ -1,12 +1,54 @@
1
1
  ---
2
2
  name: sd-worktree
3
- description: Git worktree management for branch isolation
4
- disable-model-invocation: true
3
+ description: "Git worktree branch isolation (explicit invocation only)"
5
4
  model: haiku
6
5
  ---
7
6
 
8
7
  # sd-worktree
9
8
 
9
+ ## CRITICAL SAFETY RULES — MERGE & STASH
10
+
11
+ **These rules are ABSOLUTE. No exceptions. Applies to ALL modes (yolo, normal, plan, etc.).**
12
+
13
+ 1. **NEVER run `git stash drop`, `git stash pop`, or `git stash clear`.**
14
+ - If you stashed something, ONLY use `git stash apply` (which keeps the stash intact).
15
+ - If stash is no longer needed, ASK the user before dropping it.
16
+
17
+ 2. **If `merge` fails or produces conflicts → STOP IMMEDIATELY and show this message:**
18
+ ```
19
+ ⚠️ merge 중 문제가 발생했습니다.
20
+ 직접 수동으로 merge를 진행해 주세요.
21
+ (에러 내용: <에러/충돌 정보 그대로 출력>)
22
+ ```
23
+ - Do NOT attempt to resolve conflicts yourself.
24
+ - Do NOT run `git merge --abort` without asking.
25
+ - Do NOT proceed to `clean` after a failed merge.
26
+ - Do NOT retry or work around the error.
27
+ - Just show the message above and STOP. Do nothing else.
28
+
29
+ 3. **If `rebase` fails or produces conflicts → STOP IMMEDIATELY and show this message:**
30
+ ```
31
+ ⚠️ rebase 중 문제가 발생했습니다.
32
+ 직접 수동으로 rebase를 진행해 주세요.
33
+ (에러 내용: <에러/충돌 정보 그대로 출력>)
34
+ ```
35
+ - Same rules as merge. Do NOT auto-resolve. Just show the message and STOP.
36
+
37
+ 4. **NEVER run destructive git commands during worktree workflows:**
38
+ - `git reset --hard`, `git checkout -- .`, `git restore .`, `git clean -f`
39
+ - `git branch -D` (force delete) — only `-d` (safe delete) is allowed
40
+ - `git stash drop`, `git stash pop`, `git stash clear`
41
+
42
+ 5. **Before ANY merge/rebase, verify:**
43
+ - Both main and worktree have NO uncommitted changes (`git status --porcelain`)
44
+ - If uncommitted changes exist → ask the user (do NOT auto-stash)
45
+
46
+ 6. **After merge completes, verify success before proceeding:**
47
+ - Check `git status` — if merge conflicts exist, STOP and report
48
+ - Do NOT proceed to `clean` until merge is confirmed successful
49
+
50
+ **Violation of these rules causes IRREVERSIBLE DATA LOSS.**
51
+
10
52
  ## Overview
11
53
 
12
54
  Create, merge, and clean up git worktrees under `.worktrees/`. Uses the current branch of the main working tree as the source branch.
@@ -45,6 +87,7 @@ node .claude/skills/sd-worktree/sd-worktree.mjs rebase [name]
45
87
  - Rebases the worktree branch onto the latest commit of the main branch
46
88
  - Errors if uncommitted changes exist → commit or stash first
47
89
  - Use when you want a clean history before merging
90
+ - **If rebase fails or conflicts → STOP. Report to user. Do NOT auto-resolve.**
48
91
 
49
92
  ### merge — Merge into main branch
50
93
 
@@ -57,6 +100,13 @@ node .claude/skills/sd-worktree/sd-worktree.mjs merge [name]
57
100
  - Errors if uncommitted changes exist → commit or stash first
58
101
  - After merge, always `cd <project-root>` (required for subsequent clean)
59
102
 
103
+ **MERGE SAFETY PROTOCOL:**
104
+ 1. Before merge: check BOTH main and worktree for uncommitted changes
105
+ 2. If the script exits with non-zero → show "직접 수동으로 merge해 주세요" message and STOP.
106
+ 3. After merge: run `git status` in main to confirm no conflicts
107
+ 4. If conflicts or errors → show "직접 수동으로 merge해 주세요" message and STOP.
108
+ 5. Only proceed to `clean` after confirming merge was fully successful
109
+
60
110
  ### clean — Remove worktree and delete branch
61
111
 
62
112
  ```bash
@@ -0,0 +1,2 @@
1
+ export declare function runAuthAdd(name: string, homeDir?: string): void;
2
+ //# sourceMappingURL=auth-add.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-add.d.ts","sourceRoot":"","sources":["../../src/commands/auth-add.ts"],"names":[],"mappings":"AAUA,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAyB/D"}
@@ -0,0 +1,32 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import {
4
+ validateName,
5
+ profileExists,
6
+ getProfileDir,
7
+ readCurrentAuth,
8
+ readCurrentCredentials
9
+ } from "./auth-utils.js";
10
+ function runAuthAdd(name, homeDir) {
11
+ validateName(name);
12
+ if (profileExists(name, homeDir)) {
13
+ throw new Error(
14
+ `Profile '${name}' already exists. Remove it first with: sd-claude auth remove ${name}`
15
+ );
16
+ }
17
+ const { oauthAccount, userID } = readCurrentAuth(homeDir);
18
+ const credentials = readCurrentCredentials(homeDir);
19
+ const profileDir = getProfileDir(name, homeDir);
20
+ fs.mkdirSync(profileDir, { recursive: true });
21
+ fs.writeFileSync(
22
+ path.join(profileDir, "auth.json"),
23
+ JSON.stringify({ oauthAccount, userID }, null, 2)
24
+ );
25
+ fs.writeFileSync(path.join(profileDir, "credentials.json"), JSON.stringify(credentials, null, 2));
26
+ const email = oauthAccount["emailAddress"];
27
+ console.log(`Saved profile '${name}' (${email ?? userID})`);
28
+ }
29
+ export {
30
+ runAuthAdd
31
+ };
32
+ //# sourceMappingURL=auth-add.js.map
@@ -0,0 +1,6 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/commands/auth-add.ts"],
4
+ "mappings": "AAAA,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEA,SAAS,WAAW,MAAc,SAAwB;AAC/D,eAAa,IAAI;AAEjB,MAAI,cAAc,MAAM,OAAO,GAAG;AAChC,UAAM,IAAI;AAAA,MACR,YAAY,IAAI,iEAAiE,IAAI;AAAA,IACvF;AAAA,EACF;AAEA,QAAM,EAAE,cAAc,OAAO,IAAI,gBAAgB,OAAO;AACxD,QAAM,cAAc,uBAAuB,OAAO;AAElD,QAAM,aAAa,cAAc,MAAM,OAAO;AAC9C,KAAG,UAAU,YAAY,EAAE,WAAW,KAAK,CAAC;AAE5C,KAAG;AAAA,IACD,KAAK,KAAK,YAAY,WAAW;AAAA,IACjC,KAAK,UAAU,EAAE,cAAc,OAAO,GAAG,MAAM,CAAC;AAAA,EAClD;AAEA,KAAG,cAAc,KAAK,KAAK,YAAY,kBAAkB,GAAG,KAAK,UAAU,aAAa,MAAM,CAAC,CAAC;AAEhG,QAAM,QAAQ,aAAa,cAAc;AAEzC,UAAQ,IAAI,kBAAkB,IAAI,MAAM,SAAS,MAAM,GAAG;AAC5D;",
5
+ "names": []
6
+ }
@@ -0,0 +1,2 @@
1
+ export declare function runAuthList(homeDir?: string): void;
2
+ //# sourceMappingURL=auth-list.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-list.d.ts","sourceRoot":"","sources":["../../src/commands/auth-list.ts"],"names":[],"mappings":"AAIA,wBAAgB,WAAW,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAuClD"}
@@ -0,0 +1,37 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import { listProfiles, getCurrentUserID, getProfileDir } from "./auth-utils.js";
4
+ function runAuthList(homeDir) {
5
+ const profiles = listProfiles(homeDir);
6
+ if (profiles.length === 0) {
7
+ console.log("No saved profiles.");
8
+ return;
9
+ }
10
+ const currentUserID = getCurrentUserID(homeDir);
11
+ const sorted = [...profiles].sort((a, b) => a.localeCompare(b));
12
+ for (const name of sorted) {
13
+ const profileDir = getProfileDir(name, homeDir);
14
+ const authData = JSON.parse(
15
+ fs.readFileSync(path.join(profileDir, "auth.json"), "utf-8")
16
+ );
17
+ const credData = JSON.parse(
18
+ fs.readFileSync(path.join(profileDir, "credentials.json"), "utf-8")
19
+ );
20
+ const oauthAccount = authData["oauthAccount"];
21
+ const email = oauthAccount?.["emailAddress"] ?? "";
22
+ const userID = authData["userID"];
23
+ const oauth = credData["claudeAiOauth"];
24
+ let expiresStr = "unknown";
25
+ if (oauth != null && typeof oauth["expiresAt"] === "number") {
26
+ const d = new Date(oauth["expiresAt"]);
27
+ expiresStr = `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
28
+ }
29
+ const isActive = currentUserID != null && userID === currentUserID;
30
+ const prefix = isActive ? "*" : " ";
31
+ console.log(`${prefix} ${name} (${email}) expires: ${expiresStr}`);
32
+ }
33
+ }
34
+ export {
35
+ runAuthList
36
+ };
37
+ //# sourceMappingURL=auth-list.js.map
@@ -0,0 +1,6 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/commands/auth-list.ts"],
4
+ "mappings": "AAAA,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,SAAS,cAAc,kBAAkB,qBAAqB;AAEvD,SAAS,YAAY,SAAwB;AAClD,QAAM,WAAW,aAAa,OAAO;AAErC,MAAI,SAAS,WAAW,GAAG;AAEzB,YAAQ,IAAI,oBAAoB;AAChC;AAAA,EACF;AAEA,QAAM,gBAAgB,iBAAiB,OAAO;AAC9C,QAAM,SAAS,CAAC,GAAG,QAAQ,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,cAAc,CAAC,CAAC;AAE9D,aAAW,QAAQ,QAAQ;AACzB,UAAM,aAAa,cAAc,MAAM,OAAO;AAE9C,UAAM,WAAW,KAAK;AAAA,MACpB,GAAG,aAAa,KAAK,KAAK,YAAY,WAAW,GAAG,OAAO;AAAA,IAC7D;AAEA,UAAM,WAAW,KAAK;AAAA,MACpB,GAAG,aAAa,KAAK,KAAK,YAAY,kBAAkB,GAAG,OAAO;AAAA,IACpE;AAEA,UAAM,eAAe,SAAS,cAAc;AAC5C,UAAM,QAAS,eAAe,cAAc,KAA4B;AACxE,UAAM,SAAS,SAAS,QAAQ;AAChC,UAAM,QAAQ,SAAS,eAAe;AACtC,QAAI,aAAa;AACjB,QAAI,SAAS,QAAQ,OAAO,MAAM,WAAW,MAAM,UAAU;AAC3D,YAAM,IAAI,IAAI,KAAK,MAAM,WAAW,CAAC;AACrC,mBAAa,GAAG,EAAE,YAAY,CAAC,IAAI,OAAO,EAAE,SAAS,IAAI,CAAC,EAAE,SAAS,GAAG,GAAG,CAAC,IAAI,OAAO,EAAE,QAAQ,CAAC,EAAE,SAAS,GAAG,GAAG,CAAC;AAAA,IACtH;AAEA,UAAM,WAAW,iBAAiB,QAAQ,WAAW;AACrD,UAAM,SAAS,WAAW,MAAM;AAGhC,YAAQ,IAAI,GAAG,MAAM,IAAI,IAAI,KAAK,KAAK,cAAc,UAAU,EAAE;AAAA,EACnE;AACF;",
5
+ "names": []
6
+ }
@@ -0,0 +1,2 @@
1
+ export declare function runAuthRemove(name: string, homeDir?: string): void;
2
+ //# sourceMappingURL=auth-remove.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-remove.d.ts","sourceRoot":"","sources":["../../src/commands/auth-remove.ts"],"names":[],"mappings":"AAIA,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAqBlE"}
@@ -0,0 +1,22 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import { validateName, profileExists, getProfileDir, getCurrentUserID } from "./auth-utils.js";
4
+ function runAuthRemove(name, homeDir) {
5
+ validateName(name);
6
+ if (!profileExists(name, homeDir)) {
7
+ throw new Error(`Profile '${name}' not found.`);
8
+ }
9
+ const profileDir = getProfileDir(name, homeDir);
10
+ const authJsonPath = path.join(profileDir, "auth.json");
11
+ const authData = JSON.parse(fs.readFileSync(authJsonPath, "utf-8"));
12
+ const currentUserID = getCurrentUserID(homeDir);
13
+ if (currentUserID != null && currentUserID === authData.userID) {
14
+ console.warn(`Warning: '${name}' is currently active.`);
15
+ }
16
+ fs.rmSync(profileDir, { recursive: true });
17
+ console.log(`Removed profile '${name}'`);
18
+ }
19
+ export {
20
+ runAuthRemove
21
+ };
22
+ //# sourceMappingURL=auth-remove.js.map
@@ -0,0 +1,6 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/commands/auth-remove.ts"],
4
+ "mappings": "AAAA,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,SAAS,cAAc,eAAe,eAAe,wBAAwB;AAEtE,SAAS,cAAc,MAAc,SAAwB;AAClE,eAAa,IAAI;AAEjB,MAAI,CAAC,cAAc,MAAM,OAAO,GAAG;AACjC,UAAM,IAAI,MAAM,YAAY,IAAI,cAAc;AAAA,EAChD;AAEA,QAAM,aAAa,cAAc,MAAM,OAAO;AAC9C,QAAM,eAAe,KAAK,KAAK,YAAY,WAAW;AACtD,QAAM,WAAW,KAAK,MAAM,GAAG,aAAa,cAAc,OAAO,CAAC;AAElE,QAAM,gBAAgB,iBAAiB,OAAO;AAC9C,MAAI,iBAAiB,QAAQ,kBAAkB,SAAS,QAAQ;AAE9D,YAAQ,KAAK,aAAa,IAAI,wBAAwB;AAAA,EACxD;AAEA,KAAG,OAAO,YAAY,EAAE,WAAW,KAAK,CAAC;AAGzC,UAAQ,IAAI,oBAAoB,IAAI,GAAG;AACzC;",
5
+ "names": []
6
+ }
@@ -0,0 +1,2 @@
1
+ export declare function runAuthUse(name: string, homeDir?: string): void;
2
+ //# sourceMappingURL=auth-use.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-use.d.ts","sourceRoot":"","sources":["../../src/commands/auth-use.ts"],"names":[],"mappings":"AAKA,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CA+C/D"}
@@ -0,0 +1,33 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import os from "os";
4
+ import { validateName, profileExists, getProfileDir } from "./auth-utils.js";
5
+ function runAuthUse(name, homeDir) {
6
+ validateName(name);
7
+ if (!profileExists(name, homeDir)) {
8
+ throw new Error(`Profile '${name}' not found.`);
9
+ }
10
+ const profileDir = getProfileDir(name, homeDir);
11
+ const home = homeDir ?? os.homedir();
12
+ const authJson = JSON.parse(fs.readFileSync(path.join(profileDir, "auth.json"), "utf-8"));
13
+ const savedCredentials = JSON.parse(
14
+ fs.readFileSync(path.join(profileDir, "credentials.json"), "utf-8")
15
+ );
16
+ const claudeAiOauth = savedCredentials["claudeAiOauth"];
17
+ if (claudeAiOauth?.expiresAt != null && claudeAiOauth.expiresAt < Date.now()) {
18
+ console.warn("Warning: Token expired. Run /login after switching.");
19
+ }
20
+ const claudeJsonPath = path.join(home, ".claude.json");
21
+ const claudeData = JSON.parse(fs.readFileSync(claudeJsonPath, "utf-8"));
22
+ claudeData["oauthAccount"] = authJson.oauthAccount;
23
+ claudeData["userID"] = authJson.userID;
24
+ fs.writeFileSync(claudeJsonPath, JSON.stringify(claudeData, null, 2));
25
+ const credentialsPath = path.join(home, ".claude", ".credentials.json");
26
+ fs.writeFileSync(credentialsPath, JSON.stringify(savedCredentials, null, 2));
27
+ const email = authJson.oauthAccount["emailAddress"] ?? "unknown";
28
+ console.log(`Switched to ${name} (${email})`);
29
+ }
30
+ export {
31
+ runAuthUse
32
+ };
33
+ //# sourceMappingURL=auth-use.js.map
@@ -0,0 +1,6 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/commands/auth-use.ts"],
4
+ "mappings": "AAAA,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,OAAO,QAAQ;AACf,SAAS,cAAc,eAAe,qBAAqB;AAEpD,SAAS,WAAW,MAAc,SAAwB;AAC/D,eAAa,IAAI;AAEjB,MAAI,CAAC,cAAc,MAAM,OAAO,GAAG;AACjC,UAAM,IAAI,MAAM,YAAY,IAAI,cAAc;AAAA,EAChD;AAEA,QAAM,aAAa,cAAc,MAAM,OAAO;AAC9C,QAAM,OAAO,WAAW,GAAG,QAAQ;AAGnC,QAAM,WAAW,KAAK,MAAM,GAAG,aAAa,KAAK,KAAK,YAAY,WAAW,GAAG,OAAO,CAAC;AAKxF,QAAM,mBAAmB,KAAK;AAAA,IAC5B,GAAG,aAAa,KAAK,KAAK,YAAY,kBAAkB,GAAG,OAAO;AAAA,EACpE;AAGA,QAAM,gBAAgB,iBAAiB,eAAe;AACtD,MAAI,eAAe,aAAa,QAAQ,cAAc,YAAY,KAAK,IAAI,GAAG;AAE5E,YAAQ,KAAK,qDAAqD;AAAA,EACpE;AAGA,QAAM,iBAAiB,KAAK,KAAK,MAAM,cAAc;AACrD,QAAM,aAAa,KAAK,MAAM,GAAG,aAAa,gBAAgB,OAAO,CAAC;AAKtE,aAAW,cAAc,IAAI,SAAS;AACtC,aAAW,QAAQ,IAAI,SAAS;AAEhC,KAAG,cAAc,gBAAgB,KAAK,UAAU,YAAY,MAAM,CAAC,CAAC;AAGpE,QAAM,kBAAkB,KAAK,KAAK,MAAM,WAAW,mBAAmB;AACtE,KAAG,cAAc,iBAAiB,KAAK,UAAU,kBAAkB,MAAM,CAAC,CAAC;AAG3E,QAAM,QAAS,SAAS,aAAa,cAAc,KAA4B;AAE/E,UAAQ,IAAI,eAAe,IAAI,KAAK,KAAK,GAAG;AAC9C;",
5
+ "names": []
6
+ }
@@ -0,0 +1,11 @@
1
+ export declare function validateName(name: string): void;
2
+ export declare function getProfileDir(name: string, homeDir?: string): string;
3
+ export declare function profileExists(name: string, homeDir?: string): boolean;
4
+ export declare function listProfiles(homeDir?: string): string[];
5
+ export declare function readCurrentAuth(homeDir?: string): {
6
+ oauthAccount: Record<string, unknown>;
7
+ userID: string;
8
+ };
9
+ export declare function readCurrentCredentials(homeDir?: string): Record<string, unknown>;
10
+ export declare function getCurrentUserID(homeDir?: string): string | undefined;
11
+ //# sourceMappingURL=auth-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-utils.d.ts","sourceRoot":"","sources":["../../src/commands/auth-utils.ts"],"names":[],"mappings":"AAMA,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAM/C;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAEpE;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAErE;AAED,wBAAgB,YAAY,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAUvD;AAED,wBAAgB,eAAe,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG;IACjD,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,MAAM,EAAE,MAAM,CAAC;CAChB,CAYA;AAED,wBAAgB,sBAAsB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAGhF;AAED,wBAAgB,gBAAgB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAQrE"}
@@ -0,0 +1,57 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import os from "os";
4
+ const NAME_PATTERN = /^[a-z0-9_-]+$/;
5
+ function validateName(name) {
6
+ if (!NAME_PATTERN.test(name)) {
7
+ throw new Error(
8
+ `Invalid name '${name}'. Use only lowercase letters, numbers, hyphens, underscores.`
9
+ );
10
+ }
11
+ }
12
+ function getProfileDir(name, homeDir) {
13
+ return path.join(homeDir ?? os.homedir(), ".sd-claude", "auth", name);
14
+ }
15
+ function profileExists(name, homeDir) {
16
+ return fs.existsSync(getProfileDir(name, homeDir));
17
+ }
18
+ function listProfiles(homeDir) {
19
+ const authDir = path.join(homeDir ?? os.homedir(), ".sd-claude", "auth");
20
+ if (!fs.existsSync(authDir)) {
21
+ return [];
22
+ }
23
+ return fs.readdirSync(authDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
24
+ }
25
+ function readCurrentAuth(homeDir) {
26
+ const claudeJsonPath = path.join(homeDir ?? os.homedir(), ".claude.json");
27
+ const data = JSON.parse(fs.readFileSync(claudeJsonPath, "utf-8"));
28
+ const oauthAccount = data["oauthAccount"];
29
+ const userID = data["userID"];
30
+ if (oauthAccount == null || userID == null) {
31
+ throw new Error("Not logged in. Run /login first.");
32
+ }
33
+ return { oauthAccount, userID };
34
+ }
35
+ function readCurrentCredentials(homeDir) {
36
+ const credentialsPath = path.join(homeDir ?? os.homedir(), ".claude", ".credentials.json");
37
+ return JSON.parse(fs.readFileSync(credentialsPath, "utf-8"));
38
+ }
39
+ function getCurrentUserID(homeDir) {
40
+ const claudeJsonPath = path.join(homeDir ?? os.homedir(), ".claude.json");
41
+ try {
42
+ const data = JSON.parse(fs.readFileSync(claudeJsonPath, "utf-8"));
43
+ return data["userID"];
44
+ } catch {
45
+ return void 0;
46
+ }
47
+ }
48
+ export {
49
+ getCurrentUserID,
50
+ getProfileDir,
51
+ listProfiles,
52
+ profileExists,
53
+ readCurrentAuth,
54
+ readCurrentCredentials,
55
+ validateName
56
+ };
57
+ //# sourceMappingURL=auth-utils.js.map
@@ -0,0 +1,6 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/commands/auth-utils.ts"],
4
+ "mappings": "AAAA,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,OAAO,QAAQ;AAEf,MAAM,eAAe;AAEd,SAAS,aAAa,MAAoB;AAC/C,MAAI,CAAC,aAAa,KAAK,IAAI,GAAG;AAC5B,UAAM,IAAI;AAAA,MACR,iBAAiB,IAAI;AAAA,IACvB;AAAA,EACF;AACF;AAEO,SAAS,cAAc,MAAc,SAA0B;AACpE,SAAO,KAAK,KAAK,WAAW,GAAG,QAAQ,GAAG,cAAc,QAAQ,IAAI;AACtE;AAEO,SAAS,cAAc,MAAc,SAA2B;AACrE,SAAO,GAAG,WAAW,cAAc,MAAM,OAAO,CAAC;AACnD;AAEO,SAAS,aAAa,SAA4B;AACvD,QAAM,UAAU,KAAK,KAAK,WAAW,GAAG,QAAQ,GAAG,cAAc,MAAM;AACvE,MAAI,CAAC,GAAG,WAAW,OAAO,GAAG;AAC3B,WAAO,CAAC;AAAA,EACV;AAEA,SAAO,GACJ,YAAY,SAAS,EAAE,eAAe,KAAK,CAAC,EAC5C,OAAO,CAAC,UAAU,MAAM,YAAY,CAAC,EACrC,IAAI,CAAC,UAAU,MAAM,IAAI;AAC9B;AAEO,SAAS,gBAAgB,SAG9B;AACA,QAAM,iBAAiB,KAAK,KAAK,WAAW,GAAG,QAAQ,GAAG,cAAc;AACxE,QAAM,OAAO,KAAK,MAAM,GAAG,aAAa,gBAAgB,OAAO,CAAC;AAEhE,QAAM,eAAe,KAAK,cAAc;AACxC,QAAM,SAAS,KAAK,QAAQ;AAE5B,MAAI,gBAAgB,QAAQ,UAAU,MAAM;AAC1C,UAAM,IAAI,MAAM,kCAAkC;AAAA,EACpD;AAEA,SAAO,EAAE,cAAc,OAAO;AAChC;AAEO,SAAS,uBAAuB,SAA2C;AAChF,QAAM,kBAAkB,KAAK,KAAK,WAAW,GAAG,QAAQ,GAAG,WAAW,mBAAmB;AACzF,SAAO,KAAK,MAAM,GAAG,aAAa,iBAAiB,OAAO,CAAC;AAC7D;AAEO,SAAS,iBAAiB,SAAsC;AACrE,QAAM,iBAAiB,KAAK,KAAK,WAAW,GAAG,QAAQ,GAAG,cAAc;AACxE,MAAI;AACF,UAAM,OAAO,KAAK,MAAM,GAAG,aAAa,gBAAgB,OAAO,CAAC;AAChE,WAAO,KAAK,QAAQ;AAAA,EACtB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;",
5
+ "names": []
6
+ }
@@ -8,7 +8,7 @@ function runInstall() {
8
8
  const sourceDir = path.join(pkgRoot, "claude");
9
9
  const projectRoot = findProjectRoot(__dirname);
10
10
  if (projectRoot == null) {
11
- console.log("[@simplysm/sd-claude] \uD504\uB85C\uC81D\uD2B8 \uB8E8\uD2B8\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC5B4 \uAC74\uB108\uB701\uB2C8\uB2E4.");
11
+ console.log("[@simplysm/sd-claude] Could not find project root, skipping installation.");
12
12
  return;
13
13
  }
14
14
  if (isSimplysmMonorepoSameMajor(projectRoot, pkgRoot)) {
@@ -25,9 +25,9 @@ function runInstall() {
25
25
  cleanSdEntries(targetDir);
26
26
  copySdEntries(sourceDir, targetDir, sourceEntries);
27
27
  setupStatusLine(targetDir);
28
- console.log(`[@simplysm/sd-claude] ${sourceEntries.length}\uAC1C\uC758 sd-* \uD56D\uBAA9\uC744 \uC124\uCE58\uD588\uC2B5\uB2C8\uB2E4.`);
28
+ console.log(`[@simplysm/sd-claude] Installed ${sourceEntries.length} sd-* entries.`);
29
29
  } catch (err) {
30
- console.warn("[@simplysm/sd-claude] postinstall \uACBD\uACE0:", err.message);
30
+ console.warn("[@simplysm/sd-claude] postinstall warning:", err.message);
31
31
  }
32
32
  }
33
33
  function findProjectRoot(dirname) {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/commands/install.ts"],
4
- "mappings": "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",
4
+ "mappings": "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",
5
5
  "names": []
6
6
  }
package/dist/index.d.ts CHANGED
@@ -1,2 +1,7 @@
1
1
  export * from "./commands/install.js";
2
+ export * from "./commands/auth-utils.js";
3
+ export * from "./commands/auth-add.js";
4
+ export * from "./commands/auth-use.js";
5
+ export * from "./commands/auth-list.js";
6
+ export * from "./commands/auth-remove.js";
2
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,uBAAuB,CAAC;AACtC,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,2BAA2B,CAAC"}
package/dist/index.js CHANGED
@@ -1,2 +1,7 @@
1
1
  export * from "./commands/install.js";
2
+ export * from "./commands/auth-utils.js";
3
+ export * from "./commands/auth-add.js";
4
+ export * from "./commands/auth-use.js";
5
+ export * from "./commands/auth-list.js";
6
+ export * from "./commands/auth-remove.js";
2
7
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/index.ts"],
4
- "mappings": "AACA,cAAc;",
4
+ "mappings": "AACA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;",
5
5
  "names": []
6
6
  }
package/dist/sd-claude.js CHANGED
@@ -2,12 +2,77 @@
2
2
  import yargs from "yargs";
3
3
  import { hideBin } from "yargs/helpers";
4
4
  import { runInstall } from "./commands/install.js";
5
- await yargs(hideBin(process.argv)).help("help", "\uB3C4\uC6C0\uB9D0").alias("help", "h").command(
5
+ import { runAuthAdd } from "./commands/auth-add.js";
6
+ import { runAuthUse } from "./commands/auth-use.js";
7
+ import { runAuthList } from "./commands/auth-list.js";
8
+ import { runAuthRemove } from "./commands/auth-remove.js";
9
+ await yargs(hideBin(process.argv)).help("help", "Help").alias("help", "h").command(
6
10
  "install",
7
- "Claude Code \uC5D0\uC14B\uC744 \uD504\uB85C\uC81D\uD2B8\uC5D0 \uC124\uCE58\uD55C\uB2E4.",
11
+ "Installs Claude Code assets to the project.",
8
12
  (cmd) => cmd.version(false).hide("help"),
9
13
  () => {
10
14
  runInstall();
11
15
  }
12
- ).demandCommand(1, "\uBA85\uB839\uC5B4\uB97C \uC9C0\uC815\uD574\uC8FC\uC138\uC694.").strict().parse();
16
+ ).command(
17
+ "auth",
18
+ "Manages Claude account profiles.",
19
+ (cmd) => cmd.version(false).hide("help").command(
20
+ "add <name>",
21
+ "Saves the currently logged-in account",
22
+ (sub) => sub.positional("name", {
23
+ type: "string",
24
+ demandOption: true
25
+ }),
26
+ (argv) => {
27
+ try {
28
+ runAuthAdd(argv.name);
29
+ } catch (err) {
30
+ console.error(err.message);
31
+ process.exit(1);
32
+ }
33
+ }
34
+ ).command(
35
+ "use <name>",
36
+ "Switches to a saved account",
37
+ (sub) => sub.positional("name", {
38
+ type: "string",
39
+ demandOption: true
40
+ }),
41
+ (argv) => {
42
+ try {
43
+ runAuthUse(argv.name);
44
+ } catch (err) {
45
+ console.error(err.message);
46
+ process.exit(1);
47
+ }
48
+ }
49
+ ).command(
50
+ "list",
51
+ "Displays the list of saved accounts",
52
+ (sub) => sub,
53
+ () => {
54
+ try {
55
+ runAuthList();
56
+ } catch (err) {
57
+ console.error(err.message);
58
+ process.exit(1);
59
+ }
60
+ }
61
+ ).command(
62
+ "remove <name>",
63
+ "Removes a saved account",
64
+ (sub) => sub.positional("name", {
65
+ type: "string",
66
+ demandOption: true
67
+ }),
68
+ (argv) => {
69
+ try {
70
+ runAuthRemove(argv.name);
71
+ } catch (err) {
72
+ console.error(err.message);
73
+ process.exit(1);
74
+ }
75
+ }
76
+ ).demandCommand(1, "Please specify an auth subcommand.")
77
+ ).demandCommand(1, "Please specify a command.").strict().parse();
13
78
  //# sourceMappingURL=sd-claude.js.map
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/sd-claude.ts"],
4
- "mappings": ";AAEA,OAAO,WAAW;AAClB,SAAS,eAAe;AACxB,SAAS,kBAAkB;AAE3B,MAAM,MAAM,QAAQ,QAAQ,IAAI,CAAC,EAC9B,KAAK,QAAQ,oBAAK,EAClB,MAAM,QAAQ,GAAG,EACjB;AAAA,EACC;AAAA,EACA;AAAA,EACA,CAAC,QAAQ,IAAI,QAAQ,KAAK,EAAE,KAAK,MAAM;AAAA,EACvC,MAAM;AACJ,eAAW;AAAA,EACb;AACF,EACC,cAAc,GAAG,gEAAc,EAC/B,OAAO,EACP,MAAM;",
4
+ "mappings": ";AAEA,OAAO,WAAW;AAClB,SAAS,eAAe;AACxB,SAAS,kBAAkB;AAC3B,SAAS,kBAAkB;AAC3B,SAAS,kBAAkB;AAC3B,SAAS,mBAAmB;AAC5B,SAAS,qBAAqB;AAE9B,MAAM,MAAM,QAAQ,QAAQ,IAAI,CAAC,EAC9B,KAAK,QAAQ,MAAM,EACnB,MAAM,QAAQ,GAAG,EACjB;AAAA,EACC;AAAA,EACA;AAAA,EACA,CAAC,QAAQ,IAAI,QAAQ,KAAK,EAAE,KAAK,MAAM;AAAA,EACvC,MAAM;AACJ,eAAW;AAAA,EACb;AACF,EACC;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAoC,CAAC,QACpD,IACG,QAAQ,KAAK,EACb,KAAK,MAAM,EACX;AAAA,IACC;AAAA,IACA;AAAA,IACA,CAAC,QACC,IAAI,WAAW,QAAQ;AAAA,MACrB,MAAM;AAAA,MACN,cAAc;AAAA,IAChB,CAAC;AAAA,IACH,CAAC,SAAS;AACR,UAAI;AACF,mBAAW,KAAK,IAAI;AAAA,MACtB,SAAS,KAAK;AAEZ,gBAAQ,MAAO,IAAc,OAAO;AACpC,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAAA,IACF;AAAA,EACF,EACC;AAAA,IACC;AAAA,IACA;AAAA,IACA,CAAC,QACC,IAAI,WAAW,QAAQ;AAAA,MACrB,MAAM;AAAA,MACN,cAAc;AAAA,IAChB,CAAC;AAAA,IACH,CAAC,SAAS;AACR,UAAI;AACF,mBAAW,KAAK,IAAI;AAAA,MACtB,SAAS,KAAK;AAEZ,gBAAQ,MAAO,IAAc,OAAO;AACpC,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAAA,IACF;AAAA,EACF,EACC;AAAA,IACC;AAAA,IACA;AAAA,IACA,CAAC,QAAQ;AAAA,IACT,MAAM;AACJ,UAAI;AACF,oBAAY;AAAA,MACd,SAAS,KAAK;AAEZ,gBAAQ,MAAO,IAAc,OAAO;AACpC,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAAA,IACF;AAAA,EACF,EACC;AAAA,IACC;AAAA,IACA;AAAA,IACA,CAAC,QACC,IAAI,WAAW,QAAQ;AAAA,MACrB,MAAM;AAAA,MACN,cAAc;AAAA,IAChB,CAAC;AAAA,IACH,CAAC,SAAS;AACR,UAAI;AACF,sBAAc,KAAK,IAAI;AAAA,MACzB,SAAS,KAAK;AAEZ,gBAAQ,MAAO,IAAc,OAAO;AACpC,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAAA,IACF;AAAA,EACF,EACC,cAAc,GAAG,oCAAoC;AAC1D,EACC,cAAc,GAAG,2BAA2B,EAC5C,OAAO,EACP,MAAM;",
5
5
  "names": []
6
6
  }
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@simplysm/sd-claude",
3
- "version": "13.0.69",
3
+ "version": "13.0.71",
4
4
  "description": "Simplysm Claude Code CLI — asset installer",
5
- "author": "김석래",
5
+ "author": "simplysm",
6
6
  "license": "Apache-2.0",
7
7
  "repository": {
8
8
  "type": "git",
@@ -15,6 +15,7 @@
15
15
  "files": [
16
16
  "dist",
17
17
  "src",
18
+ "tests",
18
19
  "scripts",
19
20
  "claude"
20
21
  ],
@@ -43,4 +43,4 @@ for (const entry of allEntries) {
43
43
  fs.cpSync(src, dest, { recursive: true });
44
44
  }
45
45
 
46
- console.log(`${allEntries.length}개의 sd-* 에셋을 동기화했습니다.`);
46
+ console.log(`Synchronized ${allEntries.length} sd-* assets.`);
@@ -0,0 +1,36 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import {
4
+ validateName,
5
+ profileExists,
6
+ getProfileDir,
7
+ readCurrentAuth,
8
+ readCurrentCredentials,
9
+ } from "./auth-utils.js";
10
+
11
+ export function runAuthAdd(name: string, homeDir?: string): void {
12
+ validateName(name);
13
+
14
+ if (profileExists(name, homeDir)) {
15
+ throw new Error(
16
+ `Profile '${name}' already exists. Remove it first with: sd-claude auth remove ${name}`,
17
+ );
18
+ }
19
+
20
+ const { oauthAccount, userID } = readCurrentAuth(homeDir);
21
+ const credentials = readCurrentCredentials(homeDir);
22
+
23
+ const profileDir = getProfileDir(name, homeDir);
24
+ fs.mkdirSync(profileDir, { recursive: true });
25
+
26
+ fs.writeFileSync(
27
+ path.join(profileDir, "auth.json"),
28
+ JSON.stringify({ oauthAccount, userID }, null, 2),
29
+ );
30
+
31
+ fs.writeFileSync(path.join(profileDir, "credentials.json"), JSON.stringify(credentials, null, 2));
32
+
33
+ const email = oauthAccount["emailAddress"] as string | undefined;
34
+ // eslint-disable-next-line no-console
35
+ console.log(`Saved profile '${name}' (${email ?? userID})`);
36
+ }
@@ -0,0 +1,44 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import { listProfiles, getCurrentUserID, getProfileDir } from "./auth-utils.js";
4
+
5
+ export function runAuthList(homeDir?: string): void {
6
+ const profiles = listProfiles(homeDir);
7
+
8
+ if (profiles.length === 0) {
9
+ // eslint-disable-next-line no-console
10
+ console.log("No saved profiles.");
11
+ return;
12
+ }
13
+
14
+ const currentUserID = getCurrentUserID(homeDir);
15
+ const sorted = [...profiles].sort((a, b) => a.localeCompare(b));
16
+
17
+ for (const name of sorted) {
18
+ const profileDir = getProfileDir(name, homeDir);
19
+
20
+ const authData = JSON.parse(
21
+ fs.readFileSync(path.join(profileDir, "auth.json"), "utf-8"),
22
+ ) as Record<string, unknown>;
23
+
24
+ const credData = JSON.parse(
25
+ fs.readFileSync(path.join(profileDir, "credentials.json"), "utf-8"),
26
+ ) as Record<string, unknown>;
27
+
28
+ const oauthAccount = authData["oauthAccount"] as Record<string, unknown> | undefined;
29
+ const email = (oauthAccount?.["emailAddress"] as string | undefined) ?? "";
30
+ const userID = authData["userID"] as string | undefined;
31
+ const oauth = credData["claudeAiOauth"] as Record<string, unknown> | undefined;
32
+ let expiresStr = "unknown";
33
+ if (oauth != null && typeof oauth["expiresAt"] === "number") {
34
+ const d = new Date(oauth["expiresAt"]);
35
+ expiresStr = `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
36
+ }
37
+
38
+ const isActive = currentUserID != null && userID === currentUserID;
39
+ const prefix = isActive ? "*" : " ";
40
+
41
+ // eslint-disable-next-line no-console
42
+ console.log(`${prefix} ${name} (${email}) expires: ${expiresStr}`);
43
+ }
44
+ }