@skillmarkdown/cli 0.2.0 → 0.2.1

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 CHANGED
@@ -74,6 +74,7 @@ By default, `login` uses the project’s built-in development config. You can ov
74
74
 
75
75
  - `SKILLMD_GITHUB_CLIENT_ID`
76
76
  - `SKILLMD_FIREBASE_API_KEY`
77
+ - `SKILLMD_FIREBASE_PROJECT_ID`
77
78
 
78
79
  See `.env.example` for the expected keys.
79
80
  Maintainers: built-in defaults are defined in `src/lib/auth-defaults.ts`.
@@ -94,6 +95,8 @@ skillmd login --reauth
94
95
  skillmd logout
95
96
  ```
96
97
 
98
+ `skillmd login --status` includes the authenticated Firebase project so you can confirm whether the active session is for `skillmarkdown` or `skillmarkdown-development`.
99
+
97
100
  When a saved session exists, `skillmd login` verifies the stored refresh token. If it is invalid/expired, the CLI automatically starts a new login flow. If verification is inconclusive (for example network timeout), the command exits non-zero and keeps the current session.
98
101
 
99
102
  ## Development
@@ -26,16 +26,34 @@ function parseFlags(args) {
26
26
  }
27
27
  return { status, reauth, valid: true };
28
28
  }
29
- function printSessionStatus(session) {
29
+ function formatSessionProject(session, currentConfigProjectId) {
30
+ if (!session.projectId) {
31
+ if (currentConfigProjectId) {
32
+ return { label: `unknown (current config: ${currentConfigProjectId})`, mismatch: false };
33
+ }
34
+ return { label: "unknown", mismatch: false };
35
+ }
36
+ return {
37
+ label: session.projectId,
38
+ mismatch: Boolean(currentConfigProjectId && session.projectId !== currentConfigProjectId),
39
+ };
40
+ }
41
+ function printSessionStatus(session, currentConfigProjectId) {
30
42
  if (!session) {
31
43
  console.log("Not logged in.");
32
44
  return 1;
33
45
  }
46
+ const project = formatSessionProject(session, currentConfigProjectId);
34
47
  if (session.email) {
35
- console.log(`Logged in with GitHub as ${session.email}.`);
36
- return 0;
48
+ console.log(`Logged in with GitHub as ${session.email} (project: ${project.label}).`);
49
+ }
50
+ else {
51
+ console.log(`Logged in with GitHub (uid: ${session.uid}, project: ${project.label}).`);
52
+ }
53
+ if (project.mismatch && currentConfigProjectId) {
54
+ console.log(`Current CLI config targets project '${currentConfigProjectId}'. ` +
55
+ "Run 'skillmd login --reauth' to switch projects.");
37
56
  }
38
- console.log(`Logged in with GitHub (uid: ${session.uid}).`);
39
57
  return 0;
40
58
  }
41
59
  function requireConfig(env) {
@@ -57,22 +75,29 @@ async function runLoginCommand(args, options = {}) {
57
75
  const readSessionFn = options.readSession ?? auth_session_1.readAuthSession;
58
76
  const writeSessionFn = options.writeSession ?? auth_session_1.writeAuthSession;
59
77
  const clearSessionFn = options.clearSession ?? auth_session_1.clearAuthSession;
60
- if (status) {
61
- return printSessionStatus(readSessionFn());
62
- }
63
78
  try {
64
79
  const config = requireConfig(options.env ?? process.env);
80
+ if (status) {
81
+ return printSessionStatus(readSessionFn(), config.firebaseProjectId);
82
+ }
65
83
  const existingSession = readSessionFn();
66
84
  if (existingSession && !reauth) {
67
85
  const verifyRefreshTokenFn = options.verifyRefreshToken ?? firebase_auth_1.verifyFirebaseRefreshToken;
68
86
  try {
69
87
  const validation = await verifyRefreshTokenFn(config.firebaseApiKey, existingSession.refreshToken);
70
88
  if (validation.valid) {
89
+ const project = formatSessionProject(existingSession, config.firebaseProjectId);
71
90
  if (existingSession.email) {
72
- console.log(`Already logged in as ${existingSession.email}. Run 'skillmd logout' first.`);
91
+ console.log(`Already logged in as ${existingSession.email} (project: ${project.label}). ` +
92
+ "Run 'skillmd logout' first.");
73
93
  }
74
94
  else {
75
- console.log("Already logged in. Run 'skillmd logout' first.");
95
+ console.log(`Already logged in (uid: ${existingSession.uid}, project: ${project.label}). ` +
96
+ "Run 'skillmd logout' first.");
97
+ }
98
+ if (project.mismatch) {
99
+ console.log(`Current CLI config targets project '${config.firebaseProjectId}'. ` +
100
+ "Run 'skillmd login --reauth' to switch projects.");
76
101
  }
77
102
  return 0;
78
103
  }
@@ -100,12 +125,13 @@ async function runLoginCommand(args, options = {}) {
100
125
  uid: firebaseSession.localId,
101
126
  email: firebaseSession.email,
102
127
  refreshToken: firebaseSession.refreshToken,
128
+ projectId: config.firebaseProjectId,
103
129
  });
104
130
  if (firebaseSession.email) {
105
- console.log(`Login successful. Signed in as ${firebaseSession.email}.`);
131
+ console.log(`Login successful. Signed in as ${firebaseSession.email} (project: ${config.firebaseProjectId}).`);
106
132
  }
107
133
  else {
108
- console.log("Login successful.");
134
+ console.log(`Login successful (project: ${config.firebaseProjectId}).`);
109
135
  }
110
136
  return 0;
111
137
  }
@@ -54,12 +54,14 @@ function getLoginEnvConfig(env = process.env, options = {}) {
54
54
  const dotEnv = loadDotEnv(getDefaultUserEnvPath(options));
55
55
  const githubClientId = pickValue(env.SKILLMD_GITHUB_CLIENT_ID, dotEnv.SKILLMD_GITHUB_CLIENT_ID, auth_defaults_1.DEFAULT_LOGIN_AUTH_CONFIG.githubClientId);
56
56
  const firebaseApiKey = pickValue(env.SKILLMD_FIREBASE_API_KEY, dotEnv.SKILLMD_FIREBASE_API_KEY, auth_defaults_1.DEFAULT_LOGIN_AUTH_CONFIG.firebaseApiKey);
57
- if (!githubClientId || !firebaseApiKey) {
57
+ const firebaseProjectId = pickValue(env.SKILLMD_FIREBASE_PROJECT_ID, dotEnv.SKILLMD_FIREBASE_PROJECT_ID, auth_defaults_1.DEFAULT_LOGIN_AUTH_CONFIG.firebaseProjectId);
58
+ if (!githubClientId || !firebaseApiKey || !firebaseProjectId) {
58
59
  throw new Error("missing login configuration");
59
60
  }
60
61
  return {
61
62
  githubClientId,
62
63
  firebaseApiKey,
64
+ firebaseProjectId,
63
65
  };
64
66
  }
65
67
  function getDefaultUserEnvPath(options = {}) {
@@ -5,4 +5,5 @@ exports.DEFAULT_LOGIN_AUTH_CONFIG = void 0;
5
5
  exports.DEFAULT_LOGIN_AUTH_CONFIG = Object.freeze({
6
6
  githubClientId: "Ov23lixkdtyLp35IFaBG",
7
7
  firebaseApiKey: "AIzaSyAkaZRmpCvZasFjeRAfW_b0V0nUcGOTjok",
8
+ firebaseProjectId: "skillmarkdown",
8
9
  });
@@ -28,6 +28,12 @@ function readAuthSession(sessionPath = SESSION_PATH) {
28
28
  if (parsed.email !== undefined && typeof parsed.email !== "string") {
29
29
  return null;
30
30
  }
31
+ if (parsed.projectId !== undefined && typeof parsed.projectId !== "string") {
32
+ return null;
33
+ }
34
+ if (typeof parsed.projectId === "string" && parsed.projectId.length === 0) {
35
+ return null;
36
+ }
31
37
  return parsed;
32
38
  }
33
39
  catch {
@@ -60,7 +60,9 @@ async function verifyFirebaseRefreshToken(apiKey, refreshToken) {
60
60
  }
61
61
  const errorMessage = payload.error?.message ?? "";
62
62
  if (response.status === 400 &&
63
- (errorMessage === "INVALID_REFRESH_TOKEN" || errorMessage === "TOKEN_EXPIRED")) {
63
+ (errorMessage === "INVALID_REFRESH_TOKEN" ||
64
+ errorMessage === "TOKEN_EXPIRED" ||
65
+ errorMessage === "PROJECT_NUMBER_MISMATCH")) {
64
66
  return { valid: false };
65
67
  }
66
68
  throw new Error(`Firebase token verification failed (${response.status}): ${errorMessage || "unknown error"}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skillmarkdown/cli",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "CLI for scaffolding SKILL.md-based AI skills",
5
5
  "license": "MIT",
6
6
  "type": "commonjs",