pm-skill 1.0.0 → 1.0.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/dist/linear.d.ts CHANGED
@@ -38,6 +38,13 @@ export declare function getIssue(client: LinearClient, identifier: string): Prom
38
38
  export declare function getIssueDetail(client: LinearClient, identifier: string): Promise<IssueDetail>;
39
39
  export declare function createRelation(client: LinearClient, issueId: string, relatedIssueId: string, type: "blocks" | "related" | "similar"): Promise<void>;
40
40
  export declare function createAttachment(client: LinearClient, issueId: string, url: string, title: string, subtitle?: string): Promise<void>;
41
+ export declare function createLabel(client: LinearClient, teamId: string, name: string, opts?: {
42
+ description?: string;
43
+ color?: string;
44
+ }): Promise<{
45
+ id: string;
46
+ name: string;
47
+ }>;
41
48
  export declare function getTeams(client: LinearClient): Promise<Team[]>;
42
49
  export declare function getTeamStates(client: LinearClient, teamId: string): Promise<WorkflowState[]>;
43
50
  export declare function getTeamLabels(client: LinearClient, teamId: string): Promise<IssueLabel[]>;
package/dist/linear.js CHANGED
@@ -102,6 +102,20 @@ export async function createAttachment(client, issueId, url, title, subtitle) {
102
102
  subtitle,
103
103
  });
104
104
  }
105
+ // ── Label Creation ──
106
+ export async function createLabel(client, teamId, name, opts) {
107
+ const payload = await client.createIssueLabel({
108
+ teamId,
109
+ name,
110
+ description: opts?.description,
111
+ color: opts?.color,
112
+ });
113
+ const label = await payload.issueLabel;
114
+ if (!label) {
115
+ throw new Error(`Failed to create label '${name}'.`);
116
+ }
117
+ return { id: label.id, name: label.name };
118
+ }
105
119
  // ── Team / Labels / States ──
106
120
  export async function getTeams(client) {
107
121
  const conn = await client.teams();
package/dist/workflows.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import minimist from "minimist";
3
3
  import { validateEnv, writeEnvFile, GLOBAL_DIR } from "./env.js";
4
4
  import { loadConfig, getTemplate, resolvePriority, resolveSeverity, validateDocType, validateLabel, } from "./config.js";
5
- import { getLinearClient, validateLinearKey, createIssue, getIssue, getIssueDetail, createRelation, createAttachment, getTeams, getTeamStates, getTeamLabels, resolveLabels, } from "./linear.js";
5
+ import { getLinearClient, validateLinearKey, createIssue, getIssue, getIssueDetail, createRelation, createAttachment, createLabel, getTeams, getTeamStates, getTeamLabels, resolveLabels, } from "./linear.js";
6
6
  import { getNotionClient, createTemplatedPage, createDatabaseEntry, validateNotionKey, } from "./notion.js";
7
7
  // ── Init (runs before context — no env/config validation needed) ──
8
8
  import { existsSync, copyFileSync, mkdirSync } from "fs";
@@ -115,51 +115,74 @@ async function init(args) {
115
115
  console.log(` - Run 'pm-skill setup' to verify label matching`);
116
116
  }
117
117
  // ── Commands ──
118
- async function setup(ctx) {
119
- console.log("=== PM Skill Setup ===\n");
118
+ async function setup(ctx, args) {
119
+ const sync = !!args.sync;
120
+ console.log(`=== PM Skill Setup${sync ? " (--sync)" : ""} ===\n`);
120
121
  // 1. Teams
121
122
  const teams = await getTeams(ctx.linear);
122
- console.log("📋 Linear 팀 목록:");
123
+ console.log("📋 Linear teams:");
123
124
  for (const team of teams) {
124
- const marker = team.id === ctx.env.LINEAR_DEFAULT_TEAM_ID ? " ← 현재 설정" : "";
125
+ const marker = team.id === ctx.env.LINEAR_DEFAULT_TEAM_ID ? " ← current" : "";
125
126
  console.log(` ${team.key} | ${team.name} | ${team.id}${marker}`);
126
127
  }
127
128
  // 2. States
128
129
  const teamId = ctx.env.LINEAR_DEFAULT_TEAM_ID;
129
- console.log(`\n📊 상태 목록 (${teamId}):`);
130
+ console.log(`\n📊 Workflow states (${teamId}):`);
130
131
  const states = await getTeamStates(ctx.linear, teamId);
131
132
  for (const state of states) {
132
133
  console.log(` ${state.name} (${state.type}) | ${state.id}`);
133
134
  }
134
135
  // 3. Labels + matching
135
- console.log("\n🏷️ Linear 라벨 목록:");
136
- const teamLabels = await getTeamLabels(ctx.linear, teamId);
136
+ console.log("\n🏷️ Linear labels:");
137
+ let teamLabels = await getTeamLabels(ctx.linear, teamId);
137
138
  for (const label of teamLabels) {
138
139
  console.log(` ${label.name} | ${label.id}`);
139
140
  }
140
- // 4. Config label matching
141
- console.log("\n🔗 Config ↔ Linear 라벨 매칭:");
141
+ // 4. Config label matching + sync
142
+ console.log("\n🔗 Config ↔ Linear label matching:");
142
143
  const linearLabelMap = new Map(teamLabels.map((l) => [l.name.toLowerCase(), l]));
144
+ const missingLabels = [];
143
145
  for (const configLabel of ctx.config.labels) {
144
146
  const match = linearLabelMap.get(configLabel.name.toLowerCase());
145
147
  if (match) {
146
148
  console.log(` ✅ ${configLabel.id} (${configLabel.name}) → ${match.id}`);
147
149
  }
148
150
  else {
149
- console.log(` ⚠️ ${configLabel.id} (${configLabel.name}) → 매칭 없음! Linear에 '${configLabel.name}' 라벨을 생성하세요.`);
151
+ missingLabels.push(configLabel);
152
+ console.log(` ⚠️ ${configLabel.id} (${configLabel.name}) → not found in Linear`);
150
153
  }
151
154
  }
152
- // 5. .env guide
153
- console.log("\n📝 .env 설정 안내:");
154
- console.log(" LINEAR_API_KEY=<위에서 사용 중인 키>");
155
+ // 5. Sync missing labels
156
+ if (missingLabels.length > 0 && sync) {
157
+ console.log(`\n🔄 Creating ${missingLabels.length} missing label(s) in Linear...`);
158
+ for (const configLabel of missingLabels) {
159
+ const created = await createLabel(ctx.linear, teamId, configLabel.name, {
160
+ description: configLabel.description,
161
+ color: configLabel.color,
162
+ });
163
+ console.log(` ✅ Created: ${configLabel.name} → ${created.id}`);
164
+ }
165
+ console.log("\nLabels synced successfully.");
166
+ }
167
+ else if (missingLabels.length > 0) {
168
+ console.log(`\n💡 ${missingLabels.length} label(s) missing. Run 'pm-skill setup --sync' to create them.`);
169
+ }
170
+ else {
171
+ console.log("\n✅ All config labels matched.");
172
+ }
173
+ // 6. .env guide
174
+ console.log("\n📝 .env reference:");
175
+ console.log(` LINEAR_API_KEY=<your key>`);
155
176
  console.log(` LINEAR_DEFAULT_TEAM_ID=${teamId}`);
156
177
  if (ctx.env.LINEAR_DEFAULT_PROJECT_ID) {
157
178
  console.log(` LINEAR_DEFAULT_PROJECT_ID=${ctx.env.LINEAR_DEFAULT_PROJECT_ID}`);
158
179
  }
159
180
  else {
160
- console.log(" LINEAR_DEFAULT_PROJECT_ID=<Linear 프로젝트 ID (선택)>");
181
+ console.log(" LINEAR_DEFAULT_PROJECT_ID=<optional>");
182
+ }
183
+ if (!ctx.env.NOTION_API_KEY) {
184
+ console.log(" NOTION_API_KEY=<get from https://www.notion.so/my-integrations>");
161
185
  }
162
- console.log("\nNotion 설정은 https://www.notion.so/my-integrations 에서 키를 발급하세요.");
163
186
  }
164
187
  async function startFeature(ctx, args) {
165
188
  const title = args._[0];
@@ -337,7 +360,7 @@ async function get(ctx, args) {
337
360
  }
338
361
  // ── Command Registry ──
339
362
  const COMMANDS = {
340
- setup: (ctx) => setup(ctx),
363
+ setup: (ctx, args) => setup(ctx, args),
341
364
  "start-feature": startFeature,
342
365
  "report-bug": reportBug,
343
366
  "add-task": addTask,
@@ -350,7 +373,7 @@ const COMMANDS = {
350
373
  async function main() {
351
374
  const args = minimist(process.argv.slice(2), {
352
375
  string: ["severity", "type", "url", "title", "linear-key", "notion-key", "team-id", "project-id", "notion-page"],
353
- boolean: ["global"],
376
+ boolean: ["global", "sync"],
354
377
  alias: { s: "severity", t: "type" },
355
378
  });
356
379
  const command = args._[0];
@@ -363,7 +386,7 @@ Usage: pm-skill <command> [args] [flags]
363
386
  Commands:
364
387
  init --linear-key K [--notion-key K] [--global]
365
388
  Initialize config & validate API keys
366
- setup Verify Linear/Notion connection & show config
389
+ setup [--sync] Verify config & label matching (--sync creates missing labels)
367
390
  start-feature <title> Start feature (Linear issue + Notion PRD)
368
391
  report-bug <title> [--severity S] File bug report (severity: urgent/high/medium/low)
369
392
  add-task <parent> <title> Add sub-task to an issue
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pm-skill",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Structured project management CLI — Linear + Notion integration for AI coding assistants (Claude Code, Codex)",
5
5
  "type": "module",
6
6
  "bin": {