@plosson/agentio 0.4.3 → 0.5.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plosson/agentio",
3
- "version": "0.4.3",
3
+ "version": "0.5.1",
4
4
  "description": "CLI for LLM agents to interact with communication and tracking services",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/src/auth/oauth.ts CHANGED
@@ -44,7 +44,14 @@ const GTASKS_SCOPES = [
44
44
  'https://www.googleapis.com/auth/userinfo.email', // get email for profile naming
45
45
  ];
46
46
 
47
- const SCOPES: Record<'gmail' | 'gchat' | 'gdocs' | 'gdrive-readonly' | 'gdrive-full' | 'gcal' | 'gtasks', string[]> = {
47
+ const GSHEETS_SCOPES = [
48
+ 'https://www.googleapis.com/auth/spreadsheets', // full access to spreadsheets
49
+ 'https://www.googleapis.com/auth/drive.file', // create/access files created by this app
50
+ 'https://www.googleapis.com/auth/drive.readonly', // list spreadsheets, export, copy
51
+ 'https://www.googleapis.com/auth/userinfo.email', // get email for profile naming
52
+ ];
53
+
54
+ const SCOPES: Record<'gmail' | 'gchat' | 'gdocs' | 'gdrive-readonly' | 'gdrive-full' | 'gcal' | 'gtasks' | 'gsheets', string[]> = {
48
55
  gmail: GMAIL_SCOPES,
49
56
  gchat: GCHAT_SCOPES,
50
57
  gdocs: GDOCS_SCOPES,
@@ -52,9 +59,10 @@ const SCOPES: Record<'gmail' | 'gchat' | 'gdocs' | 'gdrive-readonly' | 'gdrive-f
52
59
  'gdrive-full': GDRIVE_FULL_SCOPES,
53
60
  gcal: GCAL_SCOPES,
54
61
  gtasks: GTASKS_SCOPES,
62
+ gsheets: GSHEETS_SCOPES,
55
63
  };
56
64
 
57
- export type OAuthService = 'gmail' | 'gchat' | 'gdocs' | 'gdrive-readonly' | 'gdrive-full' | 'gcal' | 'gtasks';
65
+ export type OAuthService = 'gmail' | 'gchat' | 'gdocs' | 'gdrive-readonly' | 'gdrive-full' | 'gcal' | 'gtasks' | 'gsheets';
58
66
 
59
67
  export async function performOAuthFlow(
60
68
  service: OAuthService
@@ -8,7 +8,7 @@ import { getAllCredentials, setAllCredentials } from '../auth/token-store';
8
8
  import { CliError, handleError } from '../utils/errors';
9
9
  import { confirm } from '../utils/stdin';
10
10
  import { isInteractive, interactiveCheckbox, interactiveSelect } from '../utils/interactive';
11
- import type { Config, ServiceName } from '../types/config';
11
+ import type { Config, ServiceName, ProfileValue } from '../types/config';
12
12
  import type { StoredCredentials } from '../types/tokens';
13
13
 
14
14
  interface ProfileSelection {
@@ -126,8 +126,9 @@ export function registerConfigCommands(program: Command): void {
126
126
  const allProfiles: ProfileSelection[] = [];
127
127
  for (const [service, profiles] of Object.entries(configData.profiles)) {
128
128
  if (profiles) {
129
- for (const profile of profiles) {
130
- allProfiles.push({ service: service as ServiceName, profile });
129
+ for (const entry of profiles) {
130
+ const profileName = typeof entry === 'string' ? entry : entry.name;
131
+ allProfiles.push({ service: service as ServiceName, profile: profileName });
131
132
  }
132
133
  }
133
134
  }
@@ -309,11 +310,16 @@ export function registerConfigCommands(program: Command): void {
309
310
  for (const [service, profiles] of Object.entries(exportData.config.profiles)) {
310
311
  if (profiles) {
311
312
  if (!currentConfig.profiles[service as keyof typeof currentConfig.profiles]) {
312
- (currentConfig.profiles as Record<string, string[]>)[service] = [];
313
+ (currentConfig.profiles as Record<string, ProfileValue[]>)[service] = [];
313
314
  }
314
- for (const profile of profiles) {
315
- if (!(currentConfig.profiles as Record<string, string[]>)[service].includes(profile)) {
316
- (currentConfig.profiles as Record<string, string[]>)[service].push(profile);
315
+ for (const entry of profiles) {
316
+ const profileName = typeof entry === 'string' ? entry : entry.name;
317
+ const currentProfiles = (currentConfig.profiles as Record<string, ProfileValue[]>)[service];
318
+ const exists = currentProfiles.some((p) =>
319
+ (typeof p === 'string' ? p : p.name) === profileName
320
+ );
321
+ if (!exists) {
322
+ currentProfiles.push(entry);
317
323
  }
318
324
  }
319
325
  }
@@ -88,6 +88,7 @@ export function registerDiscourseCommands(program: Command): void {
88
88
  .command('add')
89
89
  .description('Add a new Discourse profile')
90
90
  .option('--profile <name>', 'Profile name (auto-detected from username if not provided)')
91
+ .option('--read-only', 'Create as read-only profile (blocks write operations)')
91
92
  .action(async (options) => {
92
93
  try {
93
94
  console.error('\nDiscourse Setup\n');
@@ -173,10 +174,13 @@ export function registerDiscourseCommands(program: Command): void {
173
174
  const profileName = options.profile || username.trim();
174
175
 
175
176
  // Save credentials
176
- await setProfile('discourse', profileName);
177
+ await setProfile('discourse', profileName, { readOnly: options.readOnly });
177
178
  await setCredentials('discourse', profileName, credentials);
178
179
 
179
180
  console.log(`\nProfile "${profileName}" configured!`);
181
+ if (options.readOnly) {
182
+ console.log(` Access: read-only`);
183
+ }
180
184
  console.log(` Test with: agentio discourse list --profile ${profileName}`);
181
185
  } catch (error) {
182
186
  handleError(error);