work-chronicler 0.3.0 → 0.3.2

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 (27) hide show
  1. package/.agent/skills/work-chronicler-detect-projects/SKILL.md +11 -0
  2. package/.agent/skills/work-chronicler-detect-themes/SKILL.md +11 -0
  3. package/.agent/skills/work-chronicler-generate-resume-bullets/SKILL.md +8 -1
  4. package/.agent/skills/work-chronicler-summarize-work/SKILL.md +11 -0
  5. package/.agent/skills/work-chronicler-update-resume/SKILL.md +8 -1
  6. package/.agent/skills/work-chronicler-write-self-review/SKILL.md +8 -1
  7. package/README.md +9 -1
  8. package/dist/cli/commands/analyze/reports.d.ts +1 -1
  9. package/dist/cli/commands/analyze/reports.d.ts.map +1 -1
  10. package/dist/cli/commands/analyze/reports.js +20 -2
  11. package/dist/cli/commands/fetch/all.d.ts.map +1 -1
  12. package/dist/cli/commands/fetch/all.js +5 -17
  13. package/dist/cli/commands/fetch/fetch-manager.utils.d.ts +20 -1
  14. package/dist/cli/commands/fetch/fetch-manager.utils.d.ts.map +1 -1
  15. package/dist/cli/commands/fetch/fetch-manager.utils.js +65 -0
  16. package/dist/cli/commands/fetch/github/index.d.ts.map +1 -1
  17. package/dist/cli/commands/fetch/github/index.js +5 -11
  18. package/dist/cli/commands/fetch/jira/index.d.ts.map +1 -1
  19. package/dist/cli/commands/fetch/jira/index.js +5 -13
  20. package/dist/cli/commands/init/index.js +12 -6
  21. package/dist/cli/commands/init/init.prompts.d.ts.map +1 -1
  22. package/dist/cli/commands/init/init.prompts.js +2 -2
  23. package/dist/cli/commands/init/init.utils.js +10 -1
  24. package/dist/core/types/manager.d.ts +31 -0
  25. package/dist/core/types/manager.d.ts.map +1 -1
  26. package/dist/core/types/manager.js +8 -0
  27. package/package.json +1 -1
@@ -57,6 +57,17 @@ Analyze work history to identify major projects and group related work.
57
57
  - Consider temporal clustering (work in same 2-4 week period)
58
58
  - Use PR labels and repository patterns
59
59
 
60
+ ## Output Location
61
+
62
+ **IMPORTANT:** You must do BOTH of the following:
63
+
64
+ 1. **Respond in-thread** with the project summary (for immediate feedback and MCP integration)
65
+ 2. **Save to file**: `<profile-root>/outputs/projects-detected-YYYY-MM-DD.md`
66
+
67
+ Get the profile root with: `work-chronicler workspace root`
68
+
69
+ This ensures users have both immediate feedback AND a persistent file they can reference later.
70
+
60
71
  ## Project Summary Format
61
72
 
62
73
  For each project, gather:
@@ -77,6 +77,17 @@ Work data is stored in the workspace work-log directory:
77
77
  - PR titles and descriptions keywords
78
78
  - Timeline trends (what themes emerged when?)
79
79
 
80
+ ## Output Location
81
+
82
+ **IMPORTANT:** You must do BOTH of the following:
83
+
84
+ 1. **Respond in-thread** with the themes analysis (for immediate feedback and MCP integration)
85
+ 2. **Save to file**: `<profile-root>/outputs/themes-detected-YYYY-MM-DD.md`
86
+
87
+ Get the profile root with: `work-chronicler workspace root`
88
+
89
+ This ensures users have both immediate feedback AND a persistent file they can reference later.
90
+
80
91
  ## Output Format
81
92
 
82
93
  ```markdown
@@ -66,7 +66,14 @@ Work data is stored in the workspace work-log directory:
66
66
 
67
67
  ## Output Location
68
68
 
69
- Save generated documents to `generated/resume-bullets-YYYY-MM-DD.md` in the workspace root.
69
+ **IMPORTANT:** You must do BOTH of the following:
70
+
71
+ 1. **Respond in-thread** with the resume bullets (for immediate feedback and MCP integration)
72
+ 2. **Save to file**: `<profile-root>/outputs/resume-bullets-YYYY-MM-DD.md`
73
+
74
+ Get the profile root with: `work-chronicler workspace root`
75
+
76
+ This ensures users have both immediate feedback AND a persistent file they can reference later.
70
77
 
71
78
  ## Bullet Point Format
72
79
 
@@ -65,6 +65,17 @@ Generate a summary including:
65
65
  - **Timeline**: Busiest periods, activity trends
66
66
  - **Notable Contributions**: Largest PRs, most complex changes
67
67
 
68
+ ## Output Location
69
+
70
+ **IMPORTANT:** You must do BOTH of the following:
71
+
72
+ 1. **Respond in-thread** with the work summary (for immediate feedback and MCP integration)
73
+ 2. **Save to file**: `<profile-root>/outputs/work-summary-YYYY-MM-DD.md`
74
+
75
+ Get the profile root with: `work-chronicler workspace root`
76
+
77
+ This ensures users have both immediate feedback AND a persistent file they can reference later.
78
+
68
79
  ## Example Output
69
80
 
70
81
  ```markdown
@@ -104,7 +104,14 @@ Work data is stored in the workspace work-log directory:
104
104
 
105
105
  ## Output Location
106
106
 
107
- Save generated documents to `generated/resume-updated-YYYY-MM-DD.md` in the workspace root.
107
+ **IMPORTANT:** You must do BOTH of the following:
108
+
109
+ 1. **Respond in-thread** with the resume updates (for immediate feedback and MCP integration)
110
+ 2. **Save to file**: `<profile-root>/outputs/resume-updated-YYYY-MM-DD.md`
111
+
112
+ Get the profile root with: `work-chronicler workspace root`
113
+
114
+ This ensures users have both immediate feedback AND a persistent file they can reference later.
108
115
 
109
116
  ## Output Format
110
117
 
@@ -75,7 +75,14 @@ Work data is stored in the workspace work-log directory:
75
75
 
76
76
  ## Output Location
77
77
 
78
- Save generated documents to `generated/self-review-YYYY-MM-DD.md` in the workspace root.
78
+ **IMPORTANT:** You must do BOTH of the following:
79
+
80
+ 1. **Respond in-thread** with the self-review (for immediate feedback and MCP integration)
81
+ 2. **Save to file**: `<profile-root>/outputs/self-review-YYYY-MM-DD.md`
82
+
83
+ Get the profile root with: `work-chronicler workspace root`
84
+
85
+ This ensures users have both immediate feedback AND a persistent file they can reference later.
79
86
 
80
87
  ## Output Format
81
88
 
package/README.md CHANGED
@@ -275,7 +275,15 @@ See [work-chronicler.example.yaml](work-chronicler.example.yaml) for a complete
275
275
 
276
276
  ### GitHub Token
277
277
 
278
- Create a personal access token at https://github.com/settings/tokens with the `repo` scope (or `public_repo` for public repos only).
278
+ Create a personal access token at https://github.com/settings/tokens with the following scopes:
279
+
280
+ **Required:**
281
+ - `repo` (for private repos) or `public_repo` (for public repos only)
282
+
283
+ **Required for auto-discovery with organizations:**
284
+ - `read:org` - Needed to query organization repositories during `init` auto-discovery
285
+
286
+ Without `read:org`, you can still use work-chronicler by entering repos manually during setup.
279
287
 
280
288
  ### JIRA Token
281
289
 
@@ -5,7 +5,7 @@
5
5
  */
6
6
  import { Command } from 'commander';
7
7
  /**
8
- * analyze reports <id> command
8
+ * analyze reports [id] command
9
9
  */
10
10
  export declare const reportsCommand: Command;
11
11
  //# sourceMappingURL=reports.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"reports.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/analyze/reports.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAuBH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC;;GAEG;AACH,eAAO,MAAM,cAAc,SAiTvB,CAAC"}
1
+ {"version":3,"file":"reports.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/analyze/reports.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAyBH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC;;GAEG;AACH,eAAO,MAAM,cAAc,SAmUvB,CAAC"}
@@ -7,17 +7,19 @@ import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
7
7
  import { dirname } from 'node:path';
8
8
  import { classifyPRImpact, detectProjects, generateStats, generateTimeline, } from '../../analyzer/index.js';
9
9
  import { getAnalysisFilePath, readAllPRs, readAllTickets, writeMarkdownFile, } from '../../../core/index.js';
10
+ import { select } from '@inquirer/prompts';
10
11
  import { getActiveProfile } from '../../../core/workspace/global-config.js';
12
+ import { listReports } from '../../../core/workspace/report-manager.js';
11
13
  import { getReportAnalysisDir, getReportWorkLogDir, isManagerMode, } from '../../../core/workspace/resolver.js';
12
14
  import chalk from 'chalk';
13
15
  import { Command } from 'commander';
14
16
  import ora from 'ora';
15
17
  /**
16
- * analyze reports <id> command
18
+ * analyze reports [id] command
17
19
  */
18
20
  export const reportsCommand = new Command('reports')
19
21
  .description('Generate per-report analysis (manager mode only)')
20
- .argument('<id>', 'Report ID (e.g., "alice-smith")')
22
+ .argument('[id]', 'Report ID (e.g., "alice-smith")')
21
23
  .option('--tag-prs', 'Update PR files with impact tags')
22
24
  .option('--projects', 'Detect and group related PRs/tickets into projects')
23
25
  .option('--timeline', 'Generate chronological timeline grouped by week/month')
@@ -32,6 +34,22 @@ export const reportsCommand = new Command('reports')
32
34
  process.exit(1);
33
35
  }
34
36
  const profileName = activeProfile;
37
+ // If no report ID provided, prompt to select one
38
+ if (!reportId) {
39
+ const reports = listReports(profileName);
40
+ if (reports.length === 0) {
41
+ console.error(chalk.red('\n❌ No reports configured.'));
42
+ console.log(chalk.gray('Add reports with "reports add"'));
43
+ process.exit(1);
44
+ }
45
+ reportId = await select({
46
+ message: 'Select a report to analyze:',
47
+ choices: reports.map((r) => ({
48
+ name: `${r.name} (${r.github})`,
49
+ value: r.id,
50
+ })),
51
+ });
52
+ }
35
53
  // Get report-specific paths
36
54
  const workLogDir = getReportWorkLogDir(profileName, reportId);
37
55
  const analysisDir = getReportAnalysisDir(profileName, reportId);
@@ -1 +1 @@
1
- {"version":3,"file":"all.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/fetch/all.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAwMpC,eAAO,MAAM,UAAU,SA2BnB,CAAC"}
1
+ {"version":3,"file":"all.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/fetch/all.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA8LpC,eAAO,MAAM,UAAU,SA2BnB,CAAC"}
@@ -10,7 +10,7 @@ import { isManagerMode } from '../../../core/workspace/resolver.js';
10
10
  import chalk from 'chalk';
11
11
  import { Command } from 'commander';
12
12
  import { resolveCacheBehavior } from './fetch.utils.js';
13
- import { getReportById, resolveReportIds, resolveReportOutputDir, } from './fetch-manager.utils.js';
13
+ import { buildReportConfig, getReportById, loadManagerConfigForFetch, resolveReportIds, resolveReportOutputDir, } from './fetch-manager.utils.js';
14
14
  import { fetchGitHubPRs } from './github/github.utils.js';
15
15
  import { fetchJiraTickets } from './jira/jira.utils.js';
16
16
  /**
@@ -89,28 +89,16 @@ async function fetchAllICMode(options) {
89
89
  async function fetchAllManagerMode(options) {
90
90
  const reportIds = await resolveReportIds(options);
91
91
  console.log(chalk.blue(`\n📥 Fetching all data for ${reportIds.length} report(s)...\n`));
92
- // Load config once outside loop (for efficiency)
93
- const baseConfig = await loadConfig(options.config);
92
+ // Load manager config once outside loop (for efficiency)
93
+ const managerConfig = loadManagerConfigForFetch();
94
94
  for (let i = 0; i < reportIds.length; i++) {
95
95
  const reportId = reportIds[i];
96
96
  const report = getReportById(reportId);
97
97
  console.log(chalk.blue(`\n=== Fetching data for ${report.name} (${i + 1}/${reportIds.length}) ===\n`));
98
98
  try {
99
99
  const outputDir = resolveReportOutputDir(reportId);
100
- // Override config with report's credentials
101
- const reportConfig = {
102
- ...baseConfig,
103
- github: {
104
- ...baseConfig.github,
105
- username: report.github, // Use report's GitHub username
106
- },
107
- jira: baseConfig.jira
108
- ? {
109
- ...baseConfig.jira,
110
- email: report.email, // Use report's Jira email
111
- }
112
- : undefined,
113
- };
100
+ // Build IC-compatible config from manager config + report
101
+ const reportConfig = buildReportConfig(managerConfig, report);
114
102
  // Determine cache behavior - prompt if data exists and --cache not specified
115
103
  const useCache = await resolveCacheBehavior({
116
104
  outputDir,
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * Manager mode fetch utilities
3
3
  */
4
- import type { ReportConfig } from '../../../core/types/manager.js';
4
+ import type { Config } from '../../../core/config/schema.js';
5
+ import type { ManagerConfig, ReportConfig } from '../../../core/types/manager.js';
5
6
  /**
6
7
  * Resolve report ID(s) for fetch operation
7
8
  *
@@ -26,4 +27,22 @@ export declare function getReportById(reportId: string): ReportConfig;
26
27
  * @returns Absolute path to report's work-log directory
27
28
  */
28
29
  export declare function resolveReportOutputDir(reportId: string): string;
30
+ /**
31
+ * Load and return the manager config for the active profile.
32
+ *
33
+ * @returns Manager config validated against ManagerConfigSchema
34
+ */
35
+ export declare function loadManagerConfigForFetch(): ManagerConfig;
36
+ /**
37
+ * Build an IC-compatible Config from a manager config and a specific report.
38
+ *
39
+ * The fetch utilities (fetchGitHubPRs, fetchJiraTickets, linkPRsToTickets)
40
+ * all expect a Config (IC schema). This function bridges the gap by
41
+ * constructing one from the manager config + per-report overrides.
42
+ *
43
+ * @param managerConfig - The manager profile config
44
+ * @param report - The specific report to build the config for
45
+ * @returns A Config object compatible with IC fetch utilities
46
+ */
47
+ export declare function buildReportConfig(managerConfig: ManagerConfig, report: ReportConfig): Config;
29
48
  //# sourceMappingURL=fetch-manager.utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"fetch-manager.utils.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/fetch/fetch-manager.utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAOtD;;;;;GAKG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE;IAC9C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAyDpB;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,YAAY,CAa5D;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAG/D"}
1
+ {"version":3,"file":"fetch-manager.utils.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/fetch/fetch-manager.utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAE7C,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAOrE;;;;;GAKG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE;IAC9C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAyDpB;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,YAAY,CAa5D;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAG/D;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,IAAI,aAAa,CAGzD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAC/B,aAAa,EAAE,aAAa,EAC5B,MAAM,EAAE,YAAY,GACnB,MAAM,CA+CR"}
@@ -81,3 +81,68 @@ export function resolveReportOutputDir(reportId) {
81
81
  const activeProfile = getActiveProfile();
82
82
  return getReportWorkLogDir(activeProfile, reportId);
83
83
  }
84
+ /**
85
+ * Load and return the manager config for the active profile.
86
+ *
87
+ * @returns Manager config validated against ManagerConfigSchema
88
+ */
89
+ export function loadManagerConfigForFetch() {
90
+ const activeProfile = getActiveProfile();
91
+ return loadManagerConfig(activeProfile);
92
+ }
93
+ /**
94
+ * Build an IC-compatible Config from a manager config and a specific report.
95
+ *
96
+ * The fetch utilities (fetchGitHubPRs, fetchJiraTickets, linkPRsToTickets)
97
+ * all expect a Config (IC schema). This function bridges the gap by
98
+ * constructing one from the manager config + per-report overrides.
99
+ *
100
+ * @param managerConfig - The manager profile config
101
+ * @param report - The specific report to build the config for
102
+ * @returns A Config object compatible with IC fetch utilities
103
+ */
104
+ export function buildReportConfig(managerConfig, report) {
105
+ // Build GitHub orgs array from manager org + report repos
106
+ const orgs = [
107
+ {
108
+ name: managerConfig.github.org,
109
+ repos: report.repos.length > 0 ? report.repos : ['*'],
110
+ },
111
+ ];
112
+ // Build JIRA instances from manager's JIRA config + report's projects
113
+ const jira = managerConfig.jira && report.jiraProjects.length > 0
114
+ ? {
115
+ instances: [
116
+ {
117
+ name: managerConfig.jira.host,
118
+ url: managerConfig.jira.host.startsWith('https://')
119
+ ? managerConfig.jira.host
120
+ : `https://${managerConfig.jira.host}`,
121
+ email: report.email,
122
+ token: managerConfig.jira.token,
123
+ projects: report.jiraProjects,
124
+ },
125
+ ],
126
+ }
127
+ : undefined;
128
+ return {
129
+ github: {
130
+ username: report.github,
131
+ token: managerConfig.github.token,
132
+ orgs,
133
+ },
134
+ jira,
135
+ output: { directory: './work-log' },
136
+ fetch: {
137
+ since: managerConfig.fetch.since,
138
+ until: managerConfig.fetch.until,
139
+ },
140
+ analysis: {
141
+ thresholds: {
142
+ minor: { maxLines: 20, maxFiles: 3 },
143
+ major: { minLines: 200, minFiles: 8 },
144
+ flagship: { minLines: 500, minFiles: 15 },
145
+ },
146
+ },
147
+ };
148
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/cli/commands/fetch/github/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAcH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAwHpC,eAAO,MAAM,aAAa,SA0BtB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/cli/commands/fetch/github/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAcH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAoHpC,eAAO,MAAM,aAAa,SA0BtB,CAAC"}
@@ -11,7 +11,7 @@ import { getActiveProfile } from '../../../../core/workspace/global-config.js';
11
11
  import { isManagerMode } from '../../../../core/workspace/resolver.js';
12
12
  import chalk from 'chalk';
13
13
  import { Command } from 'commander';
14
- import { getReportById, resolveReportIds, resolveReportOutputDir, } from '../fetch-manager.utils.js';
14
+ import { buildReportConfig, getReportById, loadManagerConfigForFetch, resolveReportIds, resolveReportOutputDir, } from '../fetch-manager.utils.js';
15
15
  import { fetchGitHubPRs } from './github.utils.js';
16
16
  /**
17
17
  * Fetch GitHub PRs in IC mode
@@ -43,22 +43,16 @@ async function fetchGitHubICMode(options) {
43
43
  async function fetchGitHubManagerMode(options) {
44
44
  const reportIds = await resolveReportIds(options);
45
45
  console.log(chalk.blue(`\n📥 Fetching GitHub PRs for ${reportIds.length} report(s)...\n`));
46
- // Load base config
47
- const baseConfig = await loadConfig(options.config);
46
+ // Load manager config
47
+ const managerConfig = loadManagerConfigForFetch();
48
48
  for (let i = 0; i < reportIds.length; i++) {
49
49
  const reportId = reportIds[i];
50
50
  const report = getReportById(reportId);
51
51
  console.log(chalk.blue(`\nFetching data for ${report.name} (${i + 1}/${reportIds.length})...`));
52
52
  try {
53
53
  const outputDir = resolveReportOutputDir(reportId);
54
- // Override github.username with report's username
55
- const reportConfig = {
56
- ...baseConfig,
57
- github: {
58
- ...baseConfig.github,
59
- username: report.github, // Use report's GitHub username, not manager's
60
- },
61
- };
54
+ // Build IC-compatible config from manager config + report
55
+ const reportConfig = buildReportConfig(managerConfig, report);
62
56
  // Determine cache behavior - prompt if data exists and --cache not specified
63
57
  let useCache = options.cache;
64
58
  if (!options.cache) {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/cli/commands/fetch/jira/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAcH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA2HpC,eAAO,MAAM,WAAW,SA0BpB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/cli/commands/fetch/jira/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAcH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAqHpC,eAAO,MAAM,WAAW,SA0BpB,CAAC"}
@@ -11,7 +11,7 @@ import { getActiveProfile } from '../../../../core/workspace/global-config.js';
11
11
  import { isManagerMode } from '../../../../core/workspace/resolver.js';
12
12
  import chalk from 'chalk';
13
13
  import { Command } from 'commander';
14
- import { getReportById, resolveReportIds, resolveReportOutputDir, } from '../fetch-manager.utils.js';
14
+ import { buildReportConfig, getReportById, loadManagerConfigForFetch, resolveReportIds, resolveReportOutputDir, } from '../fetch-manager.utils.js';
15
15
  import { fetchJiraTickets } from './jira.utils.js';
16
16
  /**
17
17
  * Fetch Jira tickets in IC mode
@@ -43,24 +43,16 @@ async function fetchJiraICMode(options) {
43
43
  async function fetchJiraManagerMode(options) {
44
44
  const reportIds = await resolveReportIds(options);
45
45
  console.log(chalk.blue(`\n📥 Fetching Jira tickets for ${reportIds.length} report(s)...\n`));
46
- // Load base config (will be overridden per-report)
47
- const baseConfig = await loadConfig(options.config);
46
+ // Load manager config
47
+ const managerConfig = loadManagerConfigForFetch();
48
48
  for (let i = 0; i < reportIds.length; i++) {
49
49
  const reportId = reportIds[i];
50
50
  const report = getReportById(reportId);
51
51
  console.log(chalk.blue(`\nFetching data for ${report.name} (${i + 1}/${reportIds.length})...`));
52
52
  try {
53
53
  const outputDir = resolveReportOutputDir(reportId);
54
- // Override jira.email with report's email (if Jira is configured)
55
- const reportConfig = {
56
- ...baseConfig,
57
- jira: baseConfig.jira
58
- ? {
59
- ...baseConfig.jira,
60
- email: report.email, // Use report's email, not manager's
61
- }
62
- : undefined,
63
- };
54
+ // Build IC-compatible config from manager config + report
55
+ const reportConfig = buildReportConfig(managerConfig, report);
64
56
  // Determine cache behavior - prompt if data exists and --cache not specified
65
57
  let useCache = options.cache;
66
58
  if (!options.cache) {
@@ -404,7 +404,9 @@ async function initManagerProfile(cliProfileName) {
404
404
  process.exit(1);
405
405
  }
406
406
  console.log(chalk.cyan('\nManager Mode Configuration\n'));
407
- // Step 2: GitHub configuration
407
+ // Step 2: Time range
408
+ const { since, until } = await promptTimeRange();
409
+ // Step 3: GitHub configuration
408
410
  const githubOrg = await input({
409
411
  message: 'GitHub organization:',
410
412
  validate: (value) => {
@@ -415,7 +417,7 @@ async function initManagerProfile(cliProfileName) {
415
417
  },
416
418
  });
417
419
  const githubToken = await promptGitHubTokenForManager();
418
- // Step 3: Optional JIRA configuration
420
+ // Step 4: Optional JIRA configuration
419
421
  const useJira = await confirm({
420
422
  message: 'Configure JIRA?',
421
423
  default: false,
@@ -462,16 +464,20 @@ async function initManagerProfile(cliProfileName) {
462
464
  tokens.jiraToken = jiraToken;
463
465
  tokens.jiraEmail = jiraEmail.trim();
464
466
  }
465
- // Step 4: Create manager config
467
+ // Step 5: Create manager config
466
468
  const config = {
467
469
  mode: 'manager',
468
470
  github: {
469
471
  org: githubOrg.trim(),
470
472
  },
471
473
  jira: jiraConfig,
474
+ fetch: {
475
+ since,
476
+ until,
477
+ },
472
478
  reports: [],
473
479
  };
474
- // Step 5: Create profile directories
480
+ // Step 6: Create profile directories
475
481
  ensureProfileDirs(profileName);
476
482
  // Save manager config as YAML
477
483
  const configPath = getProfileConfigPath(profileName);
@@ -485,7 +491,7 @@ async function initManagerProfile(cliProfileName) {
485
491
  // Set as active profile
486
492
  initializeWorkspaceWithProfile(profileName);
487
493
  console.log(chalk.green(`\nManager profile '${profileName}' created successfully!`));
488
- // Step 6: Add reports?
494
+ // Step 7: Add reports?
489
495
  const addReportsNow = await confirm({
490
496
  message: 'Add reports now?',
491
497
  default: true,
@@ -516,7 +522,7 @@ async function initManagerProfile(cliProfileName) {
516
522
  */
517
523
  async function promptGitHubTokenForManager() {
518
524
  console.log(chalk.dim('\nCreate a token at: https://github.com/settings/tokens'));
519
- console.log(chalk.dim('Required scopes: repo or public_repo\n'));
525
+ console.log(chalk.dim('Required scopes: repo or public_repo, read:org for orgs\n'));
520
526
  return await password({
521
527
  message: 'GitHub token:',
522
528
  validate: (value) => {
@@ -1 +1 @@
1
- {"version":3,"file":"init.prompts.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/init/init.prompts.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEpD;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,MAAM,CAAC;AAE3C;;GAEG;AACH,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,UAAU,GAAG,QAAQ,CAAC;AAEtE;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG,QAAQ,GAAG,MAAM,GAAG,KAAK,CAAC;AAE5D;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,WAAW,SAAY,GACtB,OAAO,CAAC,MAAM,CAAC,CAiBjB;AAED;;GAEG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC,CAgB/D;AAED;;GAEG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,SAAS,EAAE,SAAS,CAAC;CACtB,CAAC,CAkED;AAcD;;GAEG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,MAAM,CAAC,CAU5D;AAED;;GAEG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CA8B1D;AAED;;GAEG;AACH,wBAAsB,yBAAyB,CAC7C,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,mBAAmB,CAAC,CAyB9B;AAED;;GAEG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,eAAe,CAAC,CActE;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CA4BtE;AAED;;GAEG;AACH,wBAAsB,4BAA4B,CAChD,KAAK,EAAE,MAAM,EAAE,GACd,OAAO,CAAC,KAAK,GAAG,IAAI,GAAG,MAAM,CAAC,CAiBhC;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAKxE;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAWzE;AAED;;GAEG;AACH,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,MAAM,CAAC,CAU9D;AAED;;GAEG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC,CAqBrD;AAED;;GAEG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,MAAM,CAAC,CAavD;AAED;;GAEG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CA0B5D;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,UAAU,EAAE,GACpB,OAAO,CAAC,OAAO,CAAC,CAuBlB;AAED;;GAEG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC,CAUzD;AAED;;GAEG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,MAAM,CAAC,CAUvD;AAED;;GAEG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC,CAKvD"}
1
+ {"version":3,"file":"init.prompts.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/init/init.prompts.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEpD;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,MAAM,CAAC;AAE3C;;GAEG;AACH,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,UAAU,GAAG,QAAQ,CAAC;AAEtE;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG,QAAQ,GAAG,MAAM,GAAG,KAAK,CAAC;AAE5D;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,WAAW,SAAY,GACtB,OAAO,CAAC,MAAM,CAAC,CAiBjB;AAED;;GAEG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC,CAgB/D;AAED;;GAEG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,SAAS,EAAE,SAAS,CAAC;CACtB,CAAC,CAkED;AAcD;;GAEG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,MAAM,CAAC,CAU5D;AAED;;GAEG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CA8B1D;AAED;;GAEG;AACH,wBAAsB,yBAAyB,CAC7C,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,mBAAmB,CAAC,CAyB9B;AAED;;GAEG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,eAAe,CAAC,CActE;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CA4BtE;AAED;;GAEG;AACH,wBAAsB,4BAA4B,CAChD,KAAK,EAAE,MAAM,EAAE,GACd,OAAO,CAAC,KAAK,GAAG,IAAI,GAAG,MAAM,CAAC,CAiBhC;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAKxE;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAWzE;AAED;;GAEG;AACH,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,MAAM,CAAC,CAU9D;AAED;;GAEG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC,CAqBrD;AAED;;GAEG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,MAAM,CAAC,CAavD;AAED;;GAEG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CA0B5D;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,UAAU,EAAE,GACpB,OAAO,CAAC,OAAO,CAAC,CA2BlB;AAED;;GAEG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC,CAUzD;AAED;;GAEG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,MAAM,CAAC,CAUvD;AAED;;GAEG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC,CAKvD"}
@@ -172,7 +172,7 @@ export async function promptRepoDiscoveryMethod(org) {
172
172
  {
173
173
  name: 'Auto-discover',
174
174
  value: 'auto',
175
- description: 'Find repos where you have PRs (slow for large orgs, may miss old contributions)',
175
+ description: 'Find repos where you have PRs (requires read:org scope for orgs, slow for large orgs)',
176
176
  },
177
177
  {
178
178
  name: 'All repos (slowest)',
@@ -357,7 +357,7 @@ export async function promptTokensReady(sources) {
357
357
  console.log('Create your tokens at:');
358
358
  if (sources.includes('github')) {
359
359
  console.log(chalk.dim(' GitHub: https://github.com/settings/tokens'));
360
- console.log(chalk.dim(' (Required scopes: repo or public_repo)'));
360
+ console.log(chalk.dim(' (Required scopes: repo or public_repo, read:org for orgs)'));
361
361
  }
362
362
  if (sources.includes('jira')) {
363
363
  console.log(chalk.dim(' JIRA: https://id.atlassian.com/manage-profile/security/api-tokens'));
@@ -173,7 +173,16 @@ async function checkIfOrganization(graphqlWithAuth, login) {
173
173
  });
174
174
  return response.organization !== null;
175
175
  }
176
- catch {
176
+ catch (error) {
177
+ // Check if this is an INSUFFICIENT_SCOPES error for read:org
178
+ if (error && typeof error === 'object' && 'errors' in error) {
179
+ const errors = error.errors;
180
+ if (errors?.some((e) => e.type === 'INSUFFICIENT_SCOPES')) {
181
+ throw new Error(`GitHub token is missing the 'read:org' scope, which is required to query organizations.\n` +
182
+ `Please add this scope at: https://github.com/settings/tokens`);
183
+ }
184
+ }
185
+ // For other errors, assume it's a user (not an org)
177
186
  return false;
178
187
  }
179
188
  }
@@ -30,6 +30,19 @@ export declare const ReportConfigSchema: z.ZodObject<{
30
30
  jiraProjects?: string[] | undefined;
31
31
  }>;
32
32
  export type ReportConfig = z.infer<typeof ReportConfigSchema>;
33
+ /**
34
+ * Manager fetch configuration schema
35
+ */
36
+ export declare const ManagerFetchConfigSchema: z.ZodObject<{
37
+ since: z.ZodString;
38
+ until: z.ZodDefault<z.ZodNullable<z.ZodString>>;
39
+ }, "strip", z.ZodTypeAny, {
40
+ since: string;
41
+ until: string | null;
42
+ }, {
43
+ since: string;
44
+ until?: string | null | undefined;
45
+ }>;
33
46
  /**
34
47
  * Manager profile configuration schema
35
48
  */
@@ -58,6 +71,16 @@ export declare const ManagerConfigSchema: z.ZodObject<{
58
71
  host: string;
59
72
  token?: string | undefined;
60
73
  }>>;
74
+ fetch: z.ZodObject<{
75
+ since: z.ZodString;
76
+ until: z.ZodDefault<z.ZodNullable<z.ZodString>>;
77
+ }, "strip", z.ZodTypeAny, {
78
+ since: string;
79
+ until: string | null;
80
+ }, {
81
+ since: string;
82
+ until?: string | null | undefined;
83
+ }>;
61
84
  reports: z.ZodDefault<z.ZodArray<z.ZodObject<{
62
85
  /** Display name (e.g., "Alice Smith") */
63
86
  name: z.ZodString;
@@ -94,6 +117,10 @@ export declare const ManagerConfigSchema: z.ZodObject<{
94
117
  org: string;
95
118
  token?: string | undefined;
96
119
  };
120
+ fetch: {
121
+ since: string;
122
+ until: string | null;
123
+ };
97
124
  mode: "manager";
98
125
  jira?: {
99
126
  email: string;
@@ -105,6 +132,10 @@ export declare const ManagerConfigSchema: z.ZodObject<{
105
132
  org: string;
106
133
  token?: string | undefined;
107
134
  };
135
+ fetch: {
136
+ since: string;
137
+ until?: string | null | undefined;
138
+ };
108
139
  mode: "manager";
109
140
  reports?: {
110
141
  name: string;
@@ -1 +1 @@
1
- {"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../../src/core/types/manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;GAEG;AAEH;;GAEG;AACH,eAAO,MAAM,kBAAkB;IAC7B,yCAAyC;;IAEzC,sBAAsB;;IAEtB,wCAAwC;;IAExC,qCAAqC;;IAErC,6BAA6B;;;;;;;;;;;;;;EAE7B,CAAC;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D;;GAEG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;QAhB9B,yCAAyC;;QAEzC,sBAAsB;;QAEtB,wCAAwC;;QAExC,qCAAqC;;QAErC,6BAA6B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAsB7B,CAAC;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,gCAAgC;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,mBAAmB;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,sBAAsB;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,oBAAoB;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,iCAAiC;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,yCAAyC;IACzC,gBAAgB,EAAE,MAAM,CAAC;IACzB,sCAAsC;IACtC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB"}
1
+ {"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../../src/core/types/manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;GAEG;AAEH;;GAEG;AACH,eAAO,MAAM,kBAAkB;IAC7B,yCAAyC;;IAEzC,sBAAsB;;IAEtB,wCAAwC;;IAExC,qCAAqC;;IAErC,6BAA6B;;;;;;;;;;;;;;EAE7B,CAAC;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D;;GAEG;AACH,eAAO,MAAM,wBAAwB;;;;;;;;;EAGnC,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAxB9B,yCAAyC;;QAEzC,sBAAsB;;QAEtB,wCAAwC;;QAExC,qCAAqC;;QAErC,6BAA6B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA+B7B,CAAC;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,gCAAgC;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,mBAAmB;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,sBAAsB;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,oBAAoB;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,iCAAiC;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,yCAAyC;IACzC,gBAAgB,EAAE,MAAM,CAAC;IACzB,sCAAsC;IACtC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB"}
@@ -17,6 +17,13 @@ export const ReportConfigSchema = z.object({
17
17
  /** Jira projects to fetch */
18
18
  jiraProjects: z.array(z.string()).default([]),
19
19
  });
20
+ /**
21
+ * Manager fetch configuration schema
22
+ */
23
+ export const ManagerFetchConfigSchema = z.object({
24
+ since: z.string(),
25
+ until: z.string().nullable().default(null),
26
+ });
20
27
  /**
21
28
  * Manager profile configuration schema
22
29
  */
@@ -33,5 +40,6 @@ export const ManagerConfigSchema = z.object({
33
40
  token: z.string().optional(), // Token stored in .env, not config
34
41
  })
35
42
  .optional(),
43
+ fetch: ManagerFetchConfigSchema,
36
44
  reports: z.array(ReportConfigSchema).default([]),
37
45
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "work-chronicler",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "description": "Gather, analyze, and summarize your work history from GitHub PRs and JIRA tickets for performance reviews and resumes",
5
5
  "type": "module",
6
6
  "main": "dist/cli/index.js",