@ginkoai/cli 2.0.0-beta.2 → 2.0.0-beta.4

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 (33) hide show
  1. package/dist/commands/invite/index.d.ts +22 -0
  2. package/dist/commands/invite/index.d.ts.map +1 -0
  3. package/dist/commands/invite/index.js +192 -0
  4. package/dist/commands/invite/index.js.map +1 -0
  5. package/dist/commands/join/index.d.ts +22 -0
  6. package/dist/commands/join/index.d.ts.map +1 -0
  7. package/dist/commands/join/index.js +177 -0
  8. package/dist/commands/join/index.js.map +1 -0
  9. package/dist/commands/sync/index.d.ts +2 -1
  10. package/dist/commands/sync/index.d.ts.map +1 -1
  11. package/dist/commands/sync/index.js +6 -1
  12. package/dist/commands/sync/index.js.map +1 -1
  13. package/dist/commands/sync/sync-command.d.ts +2 -2
  14. package/dist/commands/sync/sync-command.d.ts.map +1 -1
  15. package/dist/commands/sync/sync-command.js +30 -1
  16. package/dist/commands/sync/sync-command.js.map +1 -1
  17. package/dist/commands/sync/team-sync.d.ts +32 -0
  18. package/dist/commands/sync/team-sync.d.ts.map +1 -0
  19. package/dist/commands/sync/team-sync.js +194 -0
  20. package/dist/commands/sync/team-sync.js.map +1 -0
  21. package/dist/commands/sync/types.d.ts +34 -0
  22. package/dist/commands/sync/types.d.ts.map +1 -1
  23. package/dist/commands/team/members.d.ts +3 -3
  24. package/dist/commands/team/members.d.ts.map +1 -1
  25. package/dist/commands/team/members.js +75 -12
  26. package/dist/commands/team/members.js.map +1 -1
  27. package/dist/index.js +5 -0
  28. package/dist/index.js.map +1 -1
  29. package/dist/utils/api-client.d.ts +1 -1
  30. package/dist/utils/api-client.d.ts.map +1 -1
  31. package/dist/utils/api-client.js +2 -2
  32. package/dist/utils/api-client.js.map +1 -1
  33. package/package.json +1 -1
@@ -0,0 +1,22 @@
1
+ /**
2
+ * @fileType: command
3
+ * @status: current
4
+ * @updated: 2026-01-03
5
+ * @tags: [invite, team, collaboration, epic-008]
6
+ * @related: [../join/index.ts, ../team/index.ts]
7
+ * @priority: high
8
+ * @complexity: medium
9
+ * @dependencies: [commander, chalk, ora]
10
+ */
11
+ /**
12
+ * Invite Command (EPIC-008 Sprint 1)
13
+ *
14
+ * CLI command for team owners/admins to invite members via email
15
+ */
16
+ import { Command } from 'commander';
17
+ /**
18
+ * Main invite command with subcommands
19
+ */
20
+ export declare function inviteCommand(): Command;
21
+ export default inviteCommand;
22
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/invite/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH;;;;GAIG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA8LpC;;GAEG;AACH,wBAAgB,aAAa,YA2C5B;AAED,eAAe,aAAa,CAAC"}
@@ -0,0 +1,192 @@
1
+ /**
2
+ * @fileType: command
3
+ * @status: current
4
+ * @updated: 2026-01-03
5
+ * @tags: [invite, team, collaboration, epic-008]
6
+ * @related: [../join/index.ts, ../team/index.ts]
7
+ * @priority: high
8
+ * @complexity: medium
9
+ * @dependencies: [commander, chalk, ora]
10
+ */
11
+ /**
12
+ * Invite Command (EPIC-008 Sprint 1)
13
+ *
14
+ * CLI command for team owners/admins to invite members via email
15
+ */
16
+ import { Command } from 'commander';
17
+ import chalk from 'chalk';
18
+ import ora from 'ora';
19
+ import Table from 'cli-table3';
20
+ import { api } from '../../utils/api-client.js';
21
+ /**
22
+ * Send invitation to join a team
23
+ */
24
+ async function sendInvite(email, options) {
25
+ const spinner = ora('Sending invitation...').start();
26
+ try {
27
+ // Get team ID - if not provided, use current project's default team
28
+ let teamId = options.team;
29
+ if (!teamId) {
30
+ // Try to get team from current project context
31
+ const teamsResponse = await api.get('/api/v1/teams?limit=1');
32
+ if (teamsResponse.error || !teamsResponse.data?.teams?.length) {
33
+ spinner.fail(chalk.red('No team specified and no default team found'));
34
+ console.log('');
35
+ console.log(chalk.dim('Usage: ginko invite <email> --team <team-id>'));
36
+ console.log(chalk.dim(' ginko teams list # to see available teams'));
37
+ process.exit(1);
38
+ }
39
+ teamId = teamsResponse.data.teams[0].id;
40
+ }
41
+ const response = await api.post('/api/v1/team/invite', {
42
+ team_id: teamId,
43
+ email: email.toLowerCase(),
44
+ role: options.role || 'member',
45
+ });
46
+ if (response.error) {
47
+ spinner.fail(chalk.red('Failed to send invitation'));
48
+ console.error(chalk.red(` ${response.error}`));
49
+ process.exit(1);
50
+ }
51
+ const invitation = response.data.invitation;
52
+ spinner.succeed(chalk.green('Invitation sent'));
53
+ console.log('');
54
+ console.log(chalk.bold(` Invited: ${invitation.email}`));
55
+ console.log(chalk.dim(` Team: ${invitation.team_name}`));
56
+ console.log(chalk.dim(` Role: ${invitation.role}`));
57
+ console.log(chalk.dim(` Expires: ${new Date(invitation.expires_at).toLocaleDateString()}`));
58
+ console.log('');
59
+ console.log(chalk.cyan(` Invite code: ${invitation.code}`));
60
+ console.log('');
61
+ console.log(chalk.dim('Share this code with the invitee to join:'));
62
+ console.log(chalk.green(` ginko join ${invitation.code}`));
63
+ }
64
+ catch (error) {
65
+ spinner.fail(chalk.red('Failed to send invitation'));
66
+ console.error(chalk.red(` ${error.message}`));
67
+ process.exit(1);
68
+ }
69
+ }
70
+ /**
71
+ * List pending invitations for a team
72
+ */
73
+ async function listInvites(options) {
74
+ const spinner = ora('Loading invitations...').start();
75
+ try {
76
+ let teamId = options.team;
77
+ if (!teamId) {
78
+ // Get first team
79
+ const teamsResponse = await api.get('/api/v1/teams?limit=1');
80
+ if (teamsResponse.error || !teamsResponse.data?.teams?.length) {
81
+ spinner.fail(chalk.red('No team specified and no default team found'));
82
+ process.exit(1);
83
+ }
84
+ teamId = teamsResponse.data.teams[0].id;
85
+ }
86
+ const response = await api.get(`/api/v1/team/invite?team_id=${teamId}`);
87
+ if (response.error) {
88
+ spinner.fail(chalk.red('Failed to load invitations'));
89
+ console.error(chalk.red(` ${response.error}`));
90
+ process.exit(1);
91
+ }
92
+ const invitations = response.data.invitations;
93
+ if (invitations.length === 0) {
94
+ spinner.succeed(chalk.yellow('No pending invitations'));
95
+ return;
96
+ }
97
+ spinner.succeed(chalk.green(`Found ${invitations.length} pending invitation(s)`));
98
+ console.log('');
99
+ const table = new Table({
100
+ head: [
101
+ chalk.cyan('Email'),
102
+ chalk.cyan('Role'),
103
+ chalk.cyan('Code'),
104
+ chalk.cyan('Expires'),
105
+ ],
106
+ colWidths: [30, 10, 15, 15],
107
+ wordWrap: true,
108
+ });
109
+ invitations.forEach((inv) => {
110
+ table.push([
111
+ inv.email,
112
+ inv.role,
113
+ inv.code,
114
+ new Date(inv.expires_at).toLocaleDateString(),
115
+ ]);
116
+ });
117
+ console.log(table.toString());
118
+ }
119
+ catch (error) {
120
+ spinner.fail(chalk.red('Failed to load invitations'));
121
+ console.error(chalk.red(` ${error.message}`));
122
+ process.exit(1);
123
+ }
124
+ }
125
+ /**
126
+ * Revoke a pending invitation
127
+ */
128
+ async function revokeInvite(code) {
129
+ const spinner = ora('Revoking invitation...').start();
130
+ try {
131
+ const response = await api.delete('/api/v1/team/invite', { code });
132
+ if (response.error) {
133
+ spinner.fail(chalk.red('Failed to revoke invitation'));
134
+ console.error(chalk.red(` ${response.error}`));
135
+ process.exit(1);
136
+ }
137
+ spinner.succeed(chalk.green('Invitation revoked'));
138
+ }
139
+ catch (error) {
140
+ spinner.fail(chalk.red('Failed to revoke invitation'));
141
+ console.error(chalk.red(` ${error.message}`));
142
+ process.exit(1);
143
+ }
144
+ }
145
+ /**
146
+ * Main invite command with subcommands
147
+ */
148
+ export function inviteCommand() {
149
+ const invite = new Command('invite')
150
+ .description('Invite collaborators to join your team')
151
+ .showHelpAfterError('(use --help for additional information)')
152
+ .addHelpText('after', `
153
+ ${chalk.gray('Quick Start:')}
154
+ ${chalk.green('ginko invite')} user@example.com ${chalk.gray('# Invite as member')}
155
+ ${chalk.green('ginko invite')} user@example.com --role owner ${chalk.gray('# Invite as owner')}
156
+
157
+ ${chalk.gray('Management:')}
158
+ ${chalk.green('ginko invite --list')} ${chalk.gray('# List pending invitations')}
159
+ ${chalk.green('ginko invite --revoke')} <code> ${chalk.gray('# Cancel invitation')}
160
+
161
+ ${chalk.gray('Options:')}
162
+ --team <id> ${chalk.dim('Team to invite to (defaults to your first team)')}
163
+ --role <role> ${chalk.dim('Role to assign: owner, admin, member (default: member)')}
164
+
165
+ ${chalk.gray('Workflow:')}
166
+ 1. ${chalk.green('ginko invite')} collaborator@example.com
167
+ 2. Share the invite code with them
168
+ 3. They run: ${chalk.green('ginko join')} <code>
169
+ `)
170
+ .argument('[email]', 'Email address to invite')
171
+ .option('-t, --team <id>', 'Team ID to invite to')
172
+ .option('-r, --role <role>', 'Role to assign (owner|admin|member)', 'member')
173
+ .option('-l, --list', 'List pending invitations')
174
+ .option('--revoke <code>', 'Revoke an invitation by code')
175
+ .action(async (email, options) => {
176
+ if (options.list) {
177
+ await listInvites({ team: options.team });
178
+ }
179
+ else if (options.revoke) {
180
+ await revokeInvite(options.revoke);
181
+ }
182
+ else if (email) {
183
+ await sendInvite(email, { team: options.team, role: options.role });
184
+ }
185
+ else {
186
+ invite.help({ error: false });
187
+ }
188
+ });
189
+ return invite;
190
+ }
191
+ export default inviteCommand;
192
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/invite/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * @fileType: command
3
+ * @status: current
4
+ * @updated: 2026-01-03
5
+ * @tags: [join, team, collaboration, epic-008]
6
+ * @related: [../invite/index.ts, ../team/index.ts]
7
+ * @priority: high
8
+ * @complexity: medium
9
+ * @dependencies: [commander, chalk, ora, prompts]
10
+ */
11
+ /**
12
+ * Join Command (EPIC-008 Sprint 1)
13
+ *
14
+ * CLI command for users to join a team via invitation code
15
+ */
16
+ import { Command } from 'commander';
17
+ /**
18
+ * Main join command
19
+ */
20
+ export declare function joinCommand(): Command;
21
+ export default joinCommand;
22
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/join/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH;;;;GAIG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAgLpC;;GAEG;AACH,wBAAgB,WAAW,YAqC1B;AAED,eAAe,WAAW,CAAC"}
@@ -0,0 +1,177 @@
1
+ /**
2
+ * @fileType: command
3
+ * @status: current
4
+ * @updated: 2026-01-03
5
+ * @tags: [join, team, collaboration, epic-008]
6
+ * @related: [../invite/index.ts, ../team/index.ts]
7
+ * @priority: high
8
+ * @complexity: medium
9
+ * @dependencies: [commander, chalk, ora, prompts]
10
+ */
11
+ /**
12
+ * Join Command (EPIC-008 Sprint 1)
13
+ *
14
+ * CLI command for users to join a team via invitation code
15
+ */
16
+ import { Command } from 'commander';
17
+ import chalk from 'chalk';
18
+ import ora from 'ora';
19
+ import prompts from 'prompts';
20
+ import { api } from '../../utils/api-client.js';
21
+ /**
22
+ * Validate and preview invitation
23
+ */
24
+ async function previewInvitation(code) {
25
+ const spinner = ora('Validating invitation code...').start();
26
+ try {
27
+ const response = await api.get(`/api/v1/team/join?code=${code}`);
28
+ if (response.error) {
29
+ spinner.fail(chalk.red('Invalid invitation code'));
30
+ console.error(chalk.red(` ${response.error}`));
31
+ return null;
32
+ }
33
+ spinner.succeed(chalk.green('Invitation valid'));
34
+ return response.data;
35
+ }
36
+ catch (error) {
37
+ spinner.fail(chalk.red('Failed to validate invitation'));
38
+ console.error(chalk.red(` ${error.message}`));
39
+ return null;
40
+ }
41
+ }
42
+ /**
43
+ * Accept invitation and join team
44
+ */
45
+ async function acceptInvitation(code) {
46
+ const spinner = ora('Joining team...').start();
47
+ try {
48
+ const response = await api.post('/api/v1/team/join', { code });
49
+ if (response.error) {
50
+ spinner.fail(chalk.red('Failed to join team'));
51
+ console.error(chalk.red(` ${response.error}`));
52
+ process.exit(1);
53
+ }
54
+ const result = response.data;
55
+ spinner.succeed(chalk.green(result.message));
56
+ console.log('');
57
+ console.log(chalk.bold(` Team: ${result.membership.team_name}`));
58
+ console.log(chalk.dim(` Role: ${result.membership.role}`));
59
+ console.log(chalk.dim(` Joined: ${new Date(result.membership.joined_at).toLocaleString()}`));
60
+ if (!result.email_matched) {
61
+ console.log('');
62
+ console.log(chalk.yellow(' Note: Invitation was sent to a different email.'));
63
+ }
64
+ console.log('');
65
+ console.log(chalk.dim('Next steps:'));
66
+ console.log(chalk.green(` ginko sync ${chalk.dim('# Pull team context')}`));
67
+ console.log(chalk.green(` ginko teams list-members ${chalk.dim('# See your teammates')}`));
68
+ }
69
+ catch (error) {
70
+ spinner.fail(chalk.red('Failed to join team'));
71
+ console.error(chalk.red(` ${error.message}`));
72
+ process.exit(1);
73
+ }
74
+ }
75
+ /**
76
+ * Interactive join flow (prompts for code)
77
+ */
78
+ async function interactiveJoin() {
79
+ console.log('');
80
+ console.log(chalk.cyan('Join a Team'));
81
+ console.log(chalk.dim('Enter the invitation code you received'));
82
+ console.log('');
83
+ const response = await prompts({
84
+ type: 'text',
85
+ name: 'code',
86
+ message: 'Invitation code:',
87
+ validate: (value) => value.length >= 8 || 'Code should be at least 8 characters',
88
+ });
89
+ if (!response.code) {
90
+ console.log(chalk.yellow('Cancelled'));
91
+ return;
92
+ }
93
+ await joinTeam(response.code);
94
+ }
95
+ /**
96
+ * Main join flow
97
+ */
98
+ async function joinTeam(code) {
99
+ // First validate and preview
100
+ const preview = await previewInvitation(code);
101
+ if (!preview) {
102
+ process.exit(1);
103
+ }
104
+ // Check if already a member
105
+ if (preview.already_member) {
106
+ console.log('');
107
+ console.log(chalk.yellow(`You are already a member of "${preview.team.name}"`));
108
+ console.log(chalk.dim(` Current role: ${preview.current_role}`));
109
+ process.exit(0);
110
+ }
111
+ // Show preview
112
+ console.log('');
113
+ console.log(chalk.bold('Invitation Details:'));
114
+ console.log(` Team: ${chalk.cyan(preview.team.name)}`);
115
+ console.log(` Role: ${chalk.cyan(preview.invitation.role)}`);
116
+ console.log(` Expires: ${new Date(preview.invitation.expires_at).toLocaleDateString()}`);
117
+ if (!preview.invitation.is_for_current_user) {
118
+ console.log('');
119
+ console.log(chalk.yellow(` Note: This invitation was sent to ${preview.invitation.email}`));
120
+ console.log(chalk.dim(' You can still accept it with your current account.'));
121
+ }
122
+ console.log('');
123
+ // Confirm
124
+ const confirm = await prompts({
125
+ type: 'confirm',
126
+ name: 'accept',
127
+ message: `Join team "${preview.team.name}" as ${preview.invitation.role}?`,
128
+ initial: true,
129
+ });
130
+ if (!confirm.accept) {
131
+ console.log(chalk.yellow('Cancelled'));
132
+ return;
133
+ }
134
+ // Accept
135
+ await acceptInvitation(code);
136
+ }
137
+ /**
138
+ * Main join command
139
+ */
140
+ export function joinCommand() {
141
+ const join = new Command('join')
142
+ .description('Join a team using an invitation code')
143
+ .showHelpAfterError('(use --help for additional information)')
144
+ .addHelpText('after', `
145
+ ${chalk.gray('Usage:')}
146
+ ${chalk.green('ginko join')} <invite-code> ${chalk.gray('# Join via invitation code')}
147
+ ${chalk.green('ginko join')} ${chalk.gray('# Interactive: prompts for code')}
148
+
149
+ ${chalk.gray('Workflow:')}
150
+ 1. Receive invitation code from a team owner
151
+ 2. Run: ${chalk.green('ginko join')} <code>
152
+ 3. Confirm to accept invitation
153
+ 4. Run: ${chalk.green('ginko sync')} to pull team context
154
+
155
+ ${chalk.gray('Example:')}
156
+ ${chalk.green('ginko join')} a1b2c3d4e5f6
157
+ `)
158
+ .argument('[code]', 'Invitation code')
159
+ .option('-y, --yes', 'Skip confirmation prompt')
160
+ .action(async (code, options) => {
161
+ if (code) {
162
+ if (options.yes) {
163
+ // Skip preview confirmation
164
+ await acceptInvitation(code);
165
+ }
166
+ else {
167
+ await joinTeam(code);
168
+ }
169
+ }
170
+ else {
171
+ await interactiveJoin();
172
+ }
173
+ });
174
+ return join;
175
+ }
176
+ export default joinCommand;
177
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/join/index.ts"],"names":[],"mappings":"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"}
@@ -17,5 +17,6 @@ import { Command } from 'commander';
17
17
  export declare function createSyncCommand(): Command;
18
18
  export { syncCommand } from './sync-command.js';
19
19
  export { findSprintFiles, syncSprintFile } from './sprint-syncer.js';
20
- export type { SyncOptions, SyncResult, UnsyncedNode, SprintSyncResult } from './types.js';
20
+ export { getTeamSyncStatus, updateLastSyncTimestamp, displayStalenessWarning, } from './team-sync.js';
21
+ export type { SyncOptions, SyncResult, UnsyncedNode, SprintSyncResult, TeamSyncOptions, TeamSyncStatus, } from './types.js';
21
22
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/sync/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH;;;;GAIG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,wBAAgB,iBAAiB,IAAI,OAAO,CAoB3C;AAED,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACrE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/sync/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH;;;;GAIG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,wBAAgB,iBAAiB,IAAI,OAAO,CAwB3C;AAED,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACrE,OAAO,EACL,iBAAiB,EACjB,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACV,WAAW,EACX,UAAU,EACV,YAAY,EACZ,gBAAgB,EAChB,eAAe,EACf,cAAc,GACf,MAAM,YAAY,CAAC"}
@@ -21,13 +21,17 @@ export function createSyncCommand() {
21
21
  .option('--dry-run', 'Preview changes without applying')
22
22
  .option('--force', 'Overwrite local files with graph versions')
23
23
  .option('--type <type>', 'Sync only specific node type (ADR, PRD, Pattern, Gotcha, Charter, Sprint)')
24
- .option('--no-commit', 'Sync files but do not commit');
24
+ .option('--no-commit', 'Sync files but do not commit')
25
+ .option('--staleness-days <days>', 'Days threshold for staleness warning (default: 3)', '3')
26
+ .option('--skip-team-check', 'Skip team membership verification');
25
27
  sync.action(async (options) => {
26
28
  const syncOptions = {
27
29
  dryRun: options.dryRun === true,
28
30
  force: options.force === true,
29
31
  type: options.type,
30
32
  interactive: true,
33
+ stalenessThresholdDays: parseInt(options.stalenessDays, 10) || 3,
34
+ skipMembershipCheck: options.skipTeamCheck === true,
31
35
  };
32
36
  await syncCommand(syncOptions);
33
37
  });
@@ -35,4 +39,5 @@ export function createSyncCommand() {
35
39
  }
36
40
  export { syncCommand } from './sync-command.js';
37
41
  export { findSprintFiles, syncSprintFile } from './sprint-syncer.js';
42
+ export { getTeamSyncStatus, updateLastSyncTimestamp, displayStalenessWarning, } from './team-sync.js';
38
43
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/sync/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH;;;;GAIG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGhD,MAAM,UAAU,iBAAiB;IAC/B,MAAM,IAAI,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC;SAC7B,WAAW,CAAC,uDAAuD,CAAC;SACpE,MAAM,CAAC,WAAW,EAAE,kCAAkC,CAAC;SACvD,MAAM,CAAC,SAAS,EAAE,2CAA2C,CAAC;SAC9D,MAAM,CAAC,eAAe,EAAE,2EAA2E,CAAC;SACpG,MAAM,CAAC,aAAa,EAAE,8BAA8B,CAAC,CAAC;IAEzD,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,OAAgC,EAAE,EAAE;QACrD,MAAM,WAAW,GAAgB;YAC/B,MAAM,EAAE,OAAO,CAAC,MAAM,KAAK,IAAI;YAC/B,KAAK,EAAE,OAAO,CAAC,KAAK,KAAK,IAAI;YAC7B,IAAI,EAAE,OAAO,CAAC,IAA4B;YAC1C,WAAW,EAAE,IAAI;SAClB,CAAC;QAEF,MAAM,WAAW,CAAC,WAAW,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;IAEH,OAAO,IAAI,CAAC;AACd,CAAC;AAED,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/sync/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH;;;;GAIG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGhD,MAAM,UAAU,iBAAiB;IAC/B,MAAM,IAAI,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC;SAC7B,WAAW,CAAC,uDAAuD,CAAC;SACpE,MAAM,CAAC,WAAW,EAAE,kCAAkC,CAAC;SACvD,MAAM,CAAC,SAAS,EAAE,2CAA2C,CAAC;SAC9D,MAAM,CAAC,eAAe,EAAE,2EAA2E,CAAC;SACpG,MAAM,CAAC,aAAa,EAAE,8BAA8B,CAAC;SACrD,MAAM,CAAC,yBAAyB,EAAE,mDAAmD,EAAE,GAAG,CAAC;SAC3F,MAAM,CAAC,mBAAmB,EAAE,mCAAmC,CAAC,CAAC;IAEpE,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,OAAgC,EAAE,EAAE;QACrD,MAAM,WAAW,GAAoB;YACnC,MAAM,EAAE,OAAO,CAAC,MAAM,KAAK,IAAI;YAC/B,KAAK,EAAE,OAAO,CAAC,KAAK,KAAK,IAAI;YAC7B,IAAI,EAAE,OAAO,CAAC,IAA4B;YAC1C,WAAW,EAAE,IAAI;YACjB,sBAAsB,EAAE,QAAQ,CAAC,OAAO,CAAC,aAAuB,EAAE,EAAE,CAAC,IAAI,CAAC;YAC1E,mBAAmB,EAAE,OAAO,CAAC,aAAa,KAAK,IAAI;SACpD,CAAC;QAEF,MAAM,WAAW,CAAC,WAAW,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;IAEH,OAAO,IAAI,CAAC;AACd,CAAC;AAED,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACrE,OAAO,EACL,iBAAiB,EACjB,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,gBAAgB,CAAC"}
@@ -8,9 +8,9 @@
8
8
  * @complexity: high
9
9
  * @dependencies: [chalk, prompts, simple-git]
10
10
  */
11
- import type { SyncOptions, SyncResult } from './types.js';
11
+ import type { SyncResult, TeamSyncOptions } from './types.js';
12
12
  /**
13
13
  * Main sync command implementation
14
14
  */
15
- export declare function syncCommand(options: SyncOptions): Promise<SyncResult>;
15
+ export declare function syncCommand(options: TeamSyncOptions): Promise<SyncResult>;
16
16
  //# sourceMappingURL=sync-command.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sync-command.d.ts","sourceRoot":"","sources":["../../../src/commands/sync/sync-command.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AA6BH,OAAO,KAAK,EACV,WAAW,EAEX,UAAU,EAKX,MAAM,YAAY,CAAC;AA8PpB;;GAEG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAsN3E"}
1
+ {"version":3,"file":"sync-command.d.ts","sourceRoot":"","sources":["../../../src/commands/sync/sync-command.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAmCH,OAAO,KAAK,EAGV,UAAU,EAKV,eAAe,EAChB,MAAM,YAAY,CAAC;AA8PpB;;GAEG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,UAAU,CAAC,CAwP/E"}
@@ -24,6 +24,7 @@ import prompts from 'prompts';
24
24
  import { getConfig, getApiToken } from '../graph/config.js';
25
25
  import { syncNode, getFilePath, computeHash, readFileContent, applyResolution, } from './node-syncer.js';
26
26
  import { findSprintFiles, syncSprintFile, updateCurrentSprintFile, } from './sprint-syncer.js';
27
+ import { getTeamSyncStatus, updateLastSyncTimestamp, displayStalenessWarning, displayTeamInfo, } from './team-sync.js';
27
28
  const API_BASE = process.env.GINKO_API_URL || 'https://app.ginkoai.com';
28
29
  /**
29
30
  * Transform raw API node to UnsyncedNode
@@ -236,6 +237,20 @@ export async function syncCommand(options) {
236
237
  console.error(chalk.dim(' Run `ginko login` to authenticate.'));
237
238
  return result;
238
239
  }
240
+ // Check team membership and staleness (EPIC-008)
241
+ const stalenessThreshold = options.stalenessThresholdDays ?? 3;
242
+ let teamStatus = null;
243
+ if (!options.skipMembershipCheck) {
244
+ teamStatus = await getTeamSyncStatus(graphId, token, stalenessThreshold);
245
+ // Display team info if member
246
+ if (teamStatus.isMember) {
247
+ displayTeamInfo(teamStatus);
248
+ }
249
+ // Show staleness warning if applicable
250
+ if (teamStatus.isMember && teamStatus.staleness.isStale) {
251
+ displayStalenessWarning(teamStatus);
252
+ }
253
+ }
239
254
  // Get git root directory (not cwd, which might be a subdirectory)
240
255
  let projectRoot = process.cwd();
241
256
  try {
@@ -264,8 +279,15 @@ export async function syncCommand(options) {
264
279
  console.log(chalk.green(`\n✓ Synced ${updatedSprints.length} sprint(s) and committed to git.`));
265
280
  }
266
281
  }
267
- // Summary
282
+ // Update team sync timestamp if we synced anything (EPIC-008)
268
283
  const totalUpdated = sprintResults.reduce((sum, r) => sum + r.tasksUpdated, 0);
284
+ if (totalUpdated > 0 && teamStatus?.isMember) {
285
+ const updated = await updateLastSyncTimestamp(graphId, token);
286
+ if (updated) {
287
+ console.log(chalk.dim('✓ Team sync timestamp updated'));
288
+ }
289
+ }
290
+ // Summary
269
291
  console.log(chalk.bold('\n📊 Summary:'));
270
292
  console.log(` Sprints processed: ${sprintResults.length}`);
271
293
  console.log(` Tasks updated: ${totalUpdated}`);
@@ -395,6 +417,13 @@ export async function syncCommand(options) {
395
417
  console.log(chalk.dim(' You can commit manually with: git add . && git commit'));
396
418
  }
397
419
  }
420
+ // Update team sync timestamp if we synced anything (EPIC-008)
421
+ if (result.synced.length > 0 && teamStatus?.isMember) {
422
+ const updated = await updateLastSyncTimestamp(graphId, token);
423
+ if (updated) {
424
+ console.log(chalk.dim('✓ Team sync timestamp updated'));
425
+ }
426
+ }
398
427
  // Summary
399
428
  console.log(chalk.bold('\n📊 Summary:'));
400
429
  console.log(` Synced: ${result.synced.length}`);