@togglhq/cli 1.11.226 → 1.12.0

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
@@ -31,6 +31,18 @@ Opens a browser for OAuth sign-in. On success, credentials are saved to `~/.togg
31
31
 
32
32
  Sessions refresh automatically. Re-run `toggl auth` only to switch workspaces or after 4 weeks of inactivity.
33
33
 
34
+ ### API key (CI or headless)
35
+
36
+ Set `TOGGL_API_TOKEN` to a personal API key (`toggl_sk_…`, from Toggl 2.0 **Settings → API token**). It takes precedence over saved profiles; nothing opens a browser or writes to `~/.toggl/focus-tools.json`.
37
+
38
+ ```bash
39
+ export TOGGL_API_TOKEN=toggl_sk_...
40
+ export TOGGL_ORGANIZATION_ID=4364968 # usually required: API keys cannot list organizations
41
+ toggl tasks list
42
+ ```
43
+
44
+ `TOGGL_WORKSPACE_ID` (default: your current Toggl 2.0 workspace) and `TOGGL_USER_ID` (default: looked up from the key) are optional; `--workspace-id` overrides `TOGGL_WORKSPACE_ID`. `organization …` and `shared …` commands call Toggl Accounts, which does not accept API keys, so they ask you to unset the variable and run `toggl auth`. Profile and workspace switching are disabled in this mode.
45
+
34
46
  ## Profiles
35
47
 
36
48
  Use profiles to switch between saved accounts and environments:
package/build/cli.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { a as CommanderError, i as shutdownCliTelemetry, n as captureCliException, r as initCliTelemetry, t as createProgram } from "./program-BB9t7xvO.js";
2
+ import { a as CommanderError, i as shutdownCliTelemetry, n as captureCliException, r as initCliTelemetry, t as createProgram } from "./program-BLPqhZj7.js";
3
3
  import { readFileSync } from "node:fs";
4
4
  import { dirname, join } from "node:path";
5
5
  import { fileURLToPath } from "node:url";
package/build/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { t as createProgram } from "./program-Bby4U_hT.js";
1
+ import { n as createProgram } from "./program-CxOdqdfD.js";
2
2
  export { createProgram };
package/build/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import { t as createProgram } from "./program-BB9t7xvO.js";
1
+ import { t as createProgram } from "./program-BLPqhZj7.js";
2
2
  export { createProgram };
@@ -5204,104 +5204,6 @@ var dist_default = createPrompt((config, done) => {
5204
5204
  ].filter(Boolean).join("\n").trimEnd()}${cursorHide}`;
5205
5205
  });
5206
5206
  //#endregion
5207
- //#region ../cli-core/build/profile-Empu4JWK.js
5208
- const CONFIG_DIR = path$1.join(os.homedir(), ".toggl");
5209
- const CONFIG_FILE = path$1.join(CONFIG_DIR, "focus-tools.json");
5210
- const LEGACY_MCP_CONFIG_FILE = path$1.join(os.homedir(), ".toggl-focus-mcp", "config.json");
5211
- function readJsonFile(filePath) {
5212
- if (!fs$1.existsSync(filePath)) return null;
5213
- try {
5214
- return JSON.parse(fs$1.readFileSync(filePath, "utf-8"));
5215
- } catch (err) {
5216
- const msg = err instanceof Error ? err.message : String(err);
5217
- throw new Error(`Failed to read ${filePath}: ${msg}`, { cause: err });
5218
- }
5219
- }
5220
- function saveLegacyAuthConfig(config) {
5221
- const dir = path$1.dirname(LEGACY_MCP_CONFIG_FILE);
5222
- fs$1.mkdirSync(dir, { recursive: true });
5223
- const tmp = `${LEGACY_MCP_CONFIG_FILE}.${process.pid}.tmp`;
5224
- fs$1.writeFileSync(tmp, JSON.stringify(config, null, 2) + "\n", { mode: 384 });
5225
- fs$1.renameSync(tmp, LEGACY_MCP_CONFIG_FILE);
5226
- }
5227
- function loadDeveloperToolsConfig() {
5228
- const config = readJsonFile(CONFIG_FILE);
5229
- if (!config || !config.profiles) return null;
5230
- return config;
5231
- }
5232
- function loadProfile(scope = "cli", profile) {
5233
- const config = loadDeveloperToolsConfig();
5234
- if (config) {
5235
- const activeProfile = profile ?? config.active[scope];
5236
- if (activeProfile && config.profiles[activeProfile]) return config.profiles[activeProfile];
5237
- }
5238
- const legacy = readJsonFile(LEGACY_MCP_CONFIG_FILE);
5239
- if (!legacy?.access_token || !legacy.workspace_id) return null;
5240
- return legacy;
5241
- }
5242
- function saveDeveloperToolsConfig(config) {
5243
- fs$1.mkdirSync(CONFIG_DIR, { recursive: true });
5244
- const tmp = `${CONFIG_FILE}.${process.pid}.tmp`;
5245
- fs$1.writeFileSync(tmp, JSON.stringify(config, null, 2) + "\n", { mode: 384 });
5246
- fs$1.renameSync(tmp, CONFIG_FILE);
5247
- }
5248
- function profileEnvironment(focusApiUrl) {
5249
- const hostname = new URL(focusApiUrl).hostname;
5250
- if (hostname === "focus.toggl.com") return "production";
5251
- return hostname.replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-|-$/g, "").toLowerCase();
5252
- }
5253
- function profileSlug(value, fallback) {
5254
- return (value?.split("@")[0] ?? fallback).normalize("NFKD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-|-$/g, "").toLowerCase() || fallback;
5255
- }
5256
- function deriveCliProfileName(options) {
5257
- return `${profileSlug(options.email, "user")}-${options.userId}`;
5258
- }
5259
- function toProfileRow(name, auth, activeProfile) {
5260
- const workspace = auth.workspaces?.find((candidate) => candidate.workspace_id === auth.workspace_id);
5261
- return {
5262
- name,
5263
- active: name === activeProfile,
5264
- environment: profileEnvironment(auth.focus_api_url),
5265
- user_id: auth.user_id,
5266
- organization_id: auth.organization_id,
5267
- organization_name: workspace?.organization_name,
5268
- workspace_id: auth.workspace_id,
5269
- workspace_name: auth.workspace_name,
5270
- focus_api_url: auth.focus_api_url,
5271
- accounts_api_url: auth.accounts_api_url,
5272
- authenticated_at: auth.authenticated_at,
5273
- expires_at: auth.expires_at,
5274
- token_expired: auth.expires_at <= Date.now() / 1e3
5275
- };
5276
- }
5277
- function listCliProfiles() {
5278
- const config = loadDeveloperToolsConfig();
5279
- if (!config?.profiles) return [];
5280
- return Object.entries(config.profiles).map(([name, auth]) => toProfileRow(name, auth, config.active.cli)).sort((a, b) => a.name.localeCompare(b.name));
5281
- }
5282
- function getCurrentCliProfile() {
5283
- const config = loadDeveloperToolsConfig();
5284
- const activeProfile = config?.active.cli;
5285
- if (!config?.profiles || !activeProfile || !config.profiles[activeProfile]) throw new Error("No active CLI profile. Run `toggl auth` to sign in.");
5286
- return toProfileRow(activeProfile, config.profiles[activeProfile], activeProfile);
5287
- }
5288
- function switchCliProfile(profileName) {
5289
- const config = loadDeveloperToolsConfig();
5290
- if (!config?.profiles?.[profileName]) throw new Error(`Profile '${profileName}' not found. Run \`toggl profile list\` to see profiles.`);
5291
- config.active.cli = profileName;
5292
- saveDeveloperToolsConfig(config);
5293
- return toProfileRow(profileName, config.profiles[profileName], profileName);
5294
- }
5295
- function removeCliProfile(profileName) {
5296
- const config = loadDeveloperToolsConfig();
5297
- if (!config?.profiles?.[profileName]) throw new Error(`Profile '${profileName}' not found. Run \`toggl profile list\` to see profiles.`);
5298
- const removed = toProfileRow(profileName, config.profiles[profileName], config.active.cli);
5299
- delete config.profiles[profileName];
5300
- if (config.active.cli === profileName) config.active.cli = Object.keys(config.profiles).sort()[0];
5301
- saveDeveloperToolsConfig(config);
5302
- return removed;
5303
- }
5304
- //#endregion
5305
5207
  //#region ../cli-core/build/env-CiVJIUnv.js
5306
5208
  const PRODUCTION_URLS = {
5307
5209
  focusApiUrl: "https://focus.toggl.com",
@@ -11038,7 +10940,7 @@ async function deleteMyWorkingHours(httpClient, organization_id, data, signal) {
11038
10940
  return response.json();
11039
10941
  }
11040
10942
  //#endregion
11041
- //#region ../cli-core/build/focus-client-D9JzuIl3.js
10943
+ //#region ../cli-core/build/focus-client-CGUlmnDg.js
11042
10944
  /** Request header the API reads to attribute traffic to MCP or CLI. */
11043
10945
  const TOGGL_CLIENT_HEADER = "X-Toggl-Client";
11044
10946
  /** Header the Focus API reads for analytics and presence `platform_origin`. */
@@ -12018,7 +11920,313 @@ var FocusClient = class {
12018
11920
  }
12019
11921
  };
12020
11922
  //#endregion
11923
+ //#region ../cli-core/build/profile-BNQd2PG5.js
11924
+ const CONFIG_DIR = path$1.join(os.homedir(), ".toggl");
11925
+ const CONFIG_FILE = path$1.join(CONFIG_DIR, "focus-tools.json");
11926
+ const LEGACY_MCP_CONFIG_FILE = path$1.join(os.homedir(), ".toggl-focus-mcp", "config.json");
11927
+ function readJsonFile(filePath) {
11928
+ if (!fs$1.existsSync(filePath)) return null;
11929
+ try {
11930
+ return JSON.parse(fs$1.readFileSync(filePath, "utf-8"));
11931
+ } catch (err) {
11932
+ const msg = err instanceof Error ? err.message : String(err);
11933
+ throw new Error(`Failed to read ${filePath}: ${msg}`, { cause: err });
11934
+ }
11935
+ }
11936
+ function saveLegacyAuthConfig(config) {
11937
+ const dir = path$1.dirname(LEGACY_MCP_CONFIG_FILE);
11938
+ fs$1.mkdirSync(dir, { recursive: true });
11939
+ const tmp = `${LEGACY_MCP_CONFIG_FILE}.${process.pid}.tmp`;
11940
+ fs$1.writeFileSync(tmp, JSON.stringify(config, null, 2) + "\n", { mode: 384 });
11941
+ fs$1.renameSync(tmp, LEGACY_MCP_CONFIG_FILE);
11942
+ }
11943
+ function loadDeveloperToolsConfig() {
11944
+ const config = readJsonFile(CONFIG_FILE);
11945
+ if (!config || !config.profiles) return null;
11946
+ return config;
11947
+ }
11948
+ function loadProfile(scope = "cli", profile) {
11949
+ const config = loadDeveloperToolsConfig();
11950
+ if (config) {
11951
+ const activeProfile = profile ?? config.active[scope];
11952
+ if (activeProfile && config.profiles[activeProfile]) return config.profiles[activeProfile];
11953
+ }
11954
+ const legacy = readJsonFile(LEGACY_MCP_CONFIG_FILE);
11955
+ if (!legacy?.access_token || !legacy.workspace_id) return null;
11956
+ return legacy;
11957
+ }
11958
+ function saveDeveloperToolsConfig(config) {
11959
+ fs$1.mkdirSync(CONFIG_DIR, { recursive: true });
11960
+ const tmp = `${CONFIG_FILE}.${process.pid}.tmp`;
11961
+ fs$1.writeFileSync(tmp, JSON.stringify(config, null, 2) + "\n", { mode: 384 });
11962
+ fs$1.renameSync(tmp, CONFIG_FILE);
11963
+ }
11964
+ function profileEnvironment(focusApiUrl) {
11965
+ const hostname = new URL(focusApiUrl).hostname;
11966
+ if (hostname === "focus.toggl.com") return "production";
11967
+ return hostname.replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-|-$/g, "").toLowerCase();
11968
+ }
11969
+ function profileSlug(value, fallback) {
11970
+ return (value?.split("@")[0] ?? fallback).normalize("NFKD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-|-$/g, "").toLowerCase() || fallback;
11971
+ }
11972
+ function deriveCliProfileName(options) {
11973
+ return `${profileSlug(options.email, "user")}-${options.userId}`;
11974
+ }
11975
+ function toProfileRow(name, auth, activeProfile) {
11976
+ const workspace = auth.workspaces?.find((candidate) => candidate.workspace_id === auth.workspace_id);
11977
+ return {
11978
+ name,
11979
+ active: name === activeProfile,
11980
+ environment: profileEnvironment(auth.focus_api_url),
11981
+ user_id: auth.user_id,
11982
+ organization_id: auth.organization_id,
11983
+ organization_name: workspace?.organization_name,
11984
+ workspace_id: auth.workspace_id,
11985
+ workspace_name: auth.workspace_name,
11986
+ focus_api_url: auth.focus_api_url,
11987
+ accounts_api_url: auth.accounts_api_url,
11988
+ authenticated_at: auth.authenticated_at,
11989
+ expires_at: auth.expires_at,
11990
+ token_expired: auth.expires_at <= Date.now() / 1e3
11991
+ };
11992
+ }
11993
+ function listCliProfiles() {
11994
+ const config = loadDeveloperToolsConfig();
11995
+ if (!config?.profiles) return [];
11996
+ return Object.entries(config.profiles).map(([name, auth]) => toProfileRow(name, auth, config.active.cli)).sort((a, b) => a.name.localeCompare(b.name));
11997
+ }
11998
+ function getCurrentCliProfile() {
11999
+ const config = loadDeveloperToolsConfig();
12000
+ const activeProfile = config?.active.cli;
12001
+ if (!config?.profiles || !activeProfile || !config.profiles[activeProfile]) throw new Error("No active CLI profile. Run `toggl auth` to sign in.");
12002
+ return toProfileRow(activeProfile, config.profiles[activeProfile], activeProfile);
12003
+ }
12004
+ function switchCliProfile(profileName) {
12005
+ const config = loadDeveloperToolsConfig();
12006
+ if (!config?.profiles?.[profileName]) throw new Error(`Profile '${profileName}' not found. Run \`toggl profile list\` to see profiles.`);
12007
+ config.active.cli = profileName;
12008
+ saveDeveloperToolsConfig(config);
12009
+ return toProfileRow(profileName, config.profiles[profileName], profileName);
12010
+ }
12011
+ function removeCliProfile(profileName) {
12012
+ const config = loadDeveloperToolsConfig();
12013
+ if (!config?.profiles?.[profileName]) throw new Error(`Profile '${profileName}' not found. Run \`toggl profile list\` to see profiles.`);
12014
+ const removed = toProfileRow(profileName, config.profiles[profileName], config.active.cli);
12015
+ delete config.profiles[profileName];
12016
+ if (config.active.cli === profileName) config.active.cli = Object.keys(config.profiles).sort()[0];
12017
+ saveDeveloperToolsConfig(config);
12018
+ return removed;
12019
+ }
12020
+ //#endregion
12021
12021
  //#region ../cli-core/build/index.js
12022
+ /**
12023
+ * Headless auth with a personal Toggl API key (`toggl_sk_…`).
12024
+ *
12025
+ * When `TOGGL_API_TOKEN` is set it wins over any OAuth profile: no browser, no
12026
+ * refresh, and nothing is written to `~/.toggl/focus-tools.json`. The key is sent
12027
+ * to the Toggl 2.0 API as `Authorization: Bearer toggl_sk_…`. The API never falls
12028
+ * back to session auth once a key is presented, so a bad key is a hard 401.
12029
+ *
12030
+ * API-key requests carry no Accounts session. Toggl Accounts itself only accepts
12031
+ * OAuth/session credentials, so anything that calls Accounts directly (the `org`
12032
+ * and `shared` operation families) needs an OAuth sign-in instead.
12033
+ */
12034
+ const TOGGL_API_TOKEN_ENV = "TOGGL_API_TOKEN";
12035
+ const TOGGL_USER_ID_ENV = "TOGGL_USER_ID";
12036
+ const TOGGL_WORKSPACE_ID_ENV = "TOGGL_WORKSPACE_ID";
12037
+ const TOGGL_ORGANIZATION_ID_ENV = "TOGGL_ORGANIZATION_ID";
12038
+ /** Matches `apikey.KeyPrefix` in toggl/pkg. */
12039
+ const TOGGL_API_KEY_PREFIX = "toggl_sk_";
12040
+ const REDACTED_API_TOKEN = `${TOGGL_API_KEY_PREFIX}[REDACTED]`;
12041
+ var ApiTokenAuthError = class extends Error {
12042
+ status;
12043
+ constructor(message, status) {
12044
+ super(message);
12045
+ this.name = "ApiTokenAuthError";
12046
+ this.status = status;
12047
+ }
12048
+ };
12049
+ /** The raw `TOGGL_API_TOKEN` value, trimmed; blank counts as unset. */
12050
+ function readApiTokenFromEnv(env = process.env) {
12051
+ const value = env[TOGGL_API_TOKEN_ENV]?.trim();
12052
+ return value ? value : void 0;
12053
+ }
12054
+ /** True whenever `TOGGL_API_TOKEN` is set, valid or not: a bad key must fail, not fall back to OAuth. */
12055
+ function isApiTokenMode(env = process.env) {
12056
+ return readApiTokenFromEnv(env) !== void 0;
12057
+ }
12058
+ /** Returns the key, or throws without ever echoing the value back. */
12059
+ function requireApiToken(env = process.env) {
12060
+ const token = readApiTokenFromEnv(env);
12061
+ if (!token) throw new ApiTokenAuthError(`${TOGGL_API_TOKEN_ENV} is not set.`);
12062
+ if (!token.startsWith("toggl_sk_")) throw new ApiTokenAuthError(`${TOGGL_API_TOKEN_ENV} is not a Toggl API key: keys start with "${TOGGL_API_KEY_PREFIX}". Create one in Toggl 2.0 under Settings → API token.`);
12063
+ return token;
12064
+ }
12065
+ const API_KEY_PATTERN = new RegExp(`${TOGGL_API_KEY_PREFIX}[^\\s"'\`,;)}\\]]*`, "g");
12066
+ /** Replace every `toggl_sk_…` key, plus the configured token verbatim, in free text. */
12067
+ function redactApiTokens(text, env = process.env) {
12068
+ let redacted = text.replace(API_KEY_PATTERN, REDACTED_API_TOKEN);
12069
+ const token = readApiTokenFromEnv(env);
12070
+ if (token && token.length >= 8) redacted = redacted.split(token).join(REDACTED_API_TOKEN);
12071
+ return redacted;
12072
+ }
12073
+ /** Deep-redact API keys in every string of a JSON-like value, in place where possible. */
12074
+ function redactApiTokensDeep(value, env = process.env) {
12075
+ const seen = /* @__PURE__ */ new WeakSet();
12076
+ const visit = (node) => {
12077
+ if (typeof node === "string") return redactApiTokens(node, env);
12078
+ if (!node || typeof node !== "object") return node;
12079
+ if (seen.has(node)) return node;
12080
+ seen.add(node);
12081
+ if (Array.isArray(node)) {
12082
+ for (let i = 0; i < node.length; i++) node[i] = visit(node[i]);
12083
+ return node;
12084
+ }
12085
+ const record = node;
12086
+ for (const key of Object.keys(record)) record[key] = visit(record[key]);
12087
+ return node;
12088
+ };
12089
+ return visit(value);
12090
+ }
12091
+ function parseIdEnv(env, name) {
12092
+ const raw = env[name]?.trim();
12093
+ if (!raw) return void 0;
12094
+ if (!/^\d+$/.test(raw)) throw new ApiTokenAuthError(`${name} must be a positive integer.`);
12095
+ const id = Number(raw);
12096
+ if (id <= 0 || id > Number.MAX_SAFE_INTEGER) throw new ApiTokenAuthError(`${name} must be a positive integer.`);
12097
+ return id;
12098
+ }
12099
+ function positiveId(value) {
12100
+ return typeof value === "number" && Number.isSafeInteger(value) && value > 0 ? value : void 0;
12101
+ }
12102
+ function focusApiBase(focusApiUrl) {
12103
+ const trimmed = focusApiUrl.replace(/\/+$/, "");
12104
+ return trimmed.endsWith("/api") ? trimmed : `${trimmed}/api`;
12105
+ }
12106
+ const INVALID_KEY_MESSAGE = `Toggl rejected ${TOGGL_API_TOKEN_ENV} (401). The key may have been revoked or replaced — creating a new key invalidates the previous one. Create a fresh key in Toggl 2.0 under Settings → API token.`;
12107
+ async function getJson(url, token, options) {
12108
+ const doFetch = options.fetch ?? fetch;
12109
+ const timeoutMs = options.timeoutMs ?? 1e4;
12110
+ const origin = new URL(url).origin;
12111
+ try {
12112
+ const response = await doFetch(url, {
12113
+ headers: {
12114
+ Authorization: `Bearer ${token}`,
12115
+ Accept: "application/json",
12116
+ ...togglClientHeaders(options.clientSurface)
12117
+ },
12118
+ signal: AbortSignal.timeout(timeoutMs)
12119
+ });
12120
+ if (!response.ok) return { status: response.status };
12121
+ return {
12122
+ status: response.status,
12123
+ body: await response.json()
12124
+ };
12125
+ } catch (error) {
12126
+ if (error instanceof DOMException && error.name === "TimeoutError") throw new ApiTokenAuthError(`The Toggl 2.0 API at ${origin} did not answer within ${Math.round(timeoutMs / 1e3)}s.`);
12127
+ if (error instanceof SyntaxError) throw new ApiTokenAuthError(`The Toggl 2.0 API at ${origin} returned a response that is not JSON.`);
12128
+ throw new ApiTokenAuthError(`Could not reach the Toggl 2.0 API at ${origin}: ${redactApiTokens(error instanceof Error ? error.message : String(error), options.env)}`);
12129
+ }
12130
+ }
12131
+ /**
12132
+ * Work out the user, workspace and organization the key acts in.
12133
+ *
12134
+ * Explicit values win (`--workspace-id`, then `TOGGL_*_ID`). Otherwise:
12135
+ * - user: `GET /api/accounts/me` → `user_account_id`
12136
+ * - workspace: `GET /api/users/me/settings` → `current_workspace_id`, then the
12137
+ * workspace last picked in Toggl's hosted MCP
12138
+ * - organization: the hosted-MCP selection when it names the same workspace.
12139
+ * The Toggl 2.0 API has no "my organizations" endpoint an API key can read,
12140
+ * so any other case needs `TOGGL_ORGANIZATION_ID`.
12141
+ *
12142
+ * The settings call always runs, so a revoked key fails here rather than on the
12143
+ * first tool call. The chosen pair is then checked with one org+workspace-scoped
12144
+ * read, which is what turns a wrong or foreign organization into a clear error.
12145
+ */
12146
+ async function resolveApiTokenIdentity(options) {
12147
+ const env = options.env ?? process.env;
12148
+ const token = requireApiToken(env);
12149
+ const api = focusApiBase(options.focusApiUrl);
12150
+ const envUserId = parseIdEnv(env, TOGGL_USER_ID_ENV);
12151
+ const envWorkspaceId = parseIdEnv(env, TOGGL_WORKSPACE_ID_ENV);
12152
+ const envOrganizationId = parseIdEnv(env, TOGGL_ORGANIZATION_ID_ENV);
12153
+ const settings = await getJson(`${api}/users/me/settings`, token, options);
12154
+ if (settings.status === 401) throw new ApiTokenAuthError(INVALID_KEY_MESSAGE, 401);
12155
+ if (!settings.body) throw new ApiTokenAuthError(`Could not read your Toggl 2.0 user settings (${settings.status}).`, settings.status);
12156
+ let userId = envUserId;
12157
+ let userSource = "env";
12158
+ if (userId === void 0) {
12159
+ const me = await getJson(`${api}/accounts/me`, token, options);
12160
+ if (me.status === 401) throw new ApiTokenAuthError(INVALID_KEY_MESSAGE, 401);
12161
+ userId = positiveId(me.body?.user_account_id);
12162
+ if (userId === void 0) throw new ApiTokenAuthError(`Could not determine your Toggl user ID (${me.status}). Set ${TOGGL_USER_ID_ENV}.`, me.status);
12163
+ userSource = "api";
12164
+ }
12165
+ const hostedMcpWorkspaceId = positiveId(settings.body.mcp_active_workspace_id);
12166
+ const hostedMcpOrganizationId = positiveId(settings.body.mcp_active_organization_id);
12167
+ let workspaceId;
12168
+ let workspaceSource;
12169
+ if (options.workspaceIdOverride !== void 0) {
12170
+ workspaceId = options.workspaceIdOverride;
12171
+ workspaceSource = "flag";
12172
+ } else if (envWorkspaceId !== void 0) {
12173
+ workspaceId = envWorkspaceId;
12174
+ workspaceSource = "env";
12175
+ } else {
12176
+ workspaceId = positiveId(settings.body.current_workspace_id) ?? hostedMcpWorkspaceId;
12177
+ workspaceSource = "api";
12178
+ }
12179
+ if (workspaceId === void 0) throw new ApiTokenAuthError(`Could not determine a workspace: your Toggl 2.0 settings have no current workspace. Set ${TOGGL_WORKSPACE_ID_ENV}.`);
12180
+ let organizationId = envOrganizationId;
12181
+ let organizationSource = "env";
12182
+ if (organizationId === void 0) if (hostedMcpOrganizationId !== void 0 && hostedMcpWorkspaceId === workspaceId) {
12183
+ organizationId = hostedMcpOrganizationId;
12184
+ organizationSource = "api";
12185
+ } else throw new ApiTokenAuthError(`Could not determine the organization for workspace ${workspaceId}: API keys cannot list organizations. Set ${TOGGL_ORGANIZATION_ID_ENV} (app URLs read focus.toggl.com/<organization_id>/workspaces/<workspace_id>/…).`);
12186
+ const probe = await getJson(`${api}/organizations/${organizationId}/workspaces/${workspaceId}/custom-fields`, token, options);
12187
+ if (probe.status === 401) throw new ApiTokenAuthError(INVALID_KEY_MESSAGE, 401);
12188
+ if (probe.status === 403 || probe.status === 404) throw new ApiTokenAuthError(`This API key has no access to workspace ${workspaceId} in organization ${organizationId}. Check ${TOGGL_ORGANIZATION_ID_ENV} and ${TOGGL_WORKSPACE_ID_ENV}.`, probe.status);
12189
+ if (probe.status >= 400) throw new ApiTokenAuthError(`Could not verify access to workspace ${workspaceId} in organization ${organizationId} (${probe.status}).`, probe.status);
12190
+ return {
12191
+ user_id: userId,
12192
+ organization_id: organizationId,
12193
+ workspace_id: workspaceId,
12194
+ focus_api_url: options.focusApiUrl,
12195
+ accounts_api_url: options.accountsApiUrl,
12196
+ sources: {
12197
+ user_id: userSource,
12198
+ organization_id: organizationSource,
12199
+ workspace_id: workspaceSource
12200
+ }
12201
+ };
12202
+ }
12203
+ function createApiTokenIdentityCache(options) {
12204
+ let resolved;
12205
+ let pending;
12206
+ let failure;
12207
+ return {
12208
+ resolve() {
12209
+ if (resolved) return Promise.resolve(resolved);
12210
+ pending ??= resolveApiTokenIdentity(options()).then((identity) => {
12211
+ resolved = identity;
12212
+ failure = void 0;
12213
+ return identity;
12214
+ }).catch((error) => {
12215
+ failure = error instanceof Error ? error.message : String(error);
12216
+ throw error;
12217
+ }).finally(() => {
12218
+ pending = void 0;
12219
+ });
12220
+ return pending;
12221
+ },
12222
+ peek: () => resolved,
12223
+ lastError: () => failure
12224
+ };
12225
+ }
12226
+ /** Text every OAuth-only surface returns while `TOGGL_API_TOKEN` is set. */
12227
+ function oauthRequiredMessage(subject, authCommand) {
12228
+ return `${subject} requires OAuth sign-in (run auth): it calls Toggl Accounts, which does not accept API keys. Unset ${TOGGL_API_TOKEN_ENV} and run \`${authCommand}\` to use it.`;
12229
+ }
12022
12230
  function openAuthBrowser(url) {
12023
12231
  const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start \"\"" : "xdg-open";
12024
12232
  exec(`${cmd} "${url}"`, (err) => {
@@ -12643,6 +12851,7 @@ async function refreshTokens(accountsApiUrl, refreshToken, clientSurface, client
12643
12851
  return response.json();
12644
12852
  }
12645
12853
  async function getValidToken(scope = "cli", profile) {
12854
+ if (isApiTokenMode()) return requireApiToken();
12646
12855
  const authConfig = loadProfile(scope, profile);
12647
12856
  if (!authConfig) throw new Error(scope === "cli" ? "Not authenticated. Run `toggl auth` to sign in." : `Not authenticated. Run \`${npxMcpAuthCommand()}\` to sign in.`);
12648
12857
  const now = Date.now() / 1e3;
@@ -12862,7 +13071,7 @@ function scrubSpan(span) {
12862
13071
  /**
12863
13072
  * Last word on every event the public build sends: messages reduced to fixed
12864
13073
  * categories, no hostname, no breadcrumbs, no dependency list, no request data,
12865
- * package-relative stack paths, and no query strings on spans.
13074
+ * package-relative stack paths, no query strings on spans, and no API keys.
12866
13075
  */
12867
13076
  function scrubPublicSentryEvent(event) {
12868
13077
  redactUnsafeSentryMessages(event);
@@ -12874,7 +13083,7 @@ function scrubPublicSentryEvent(event) {
12874
13083
  for (const thread of event.threads?.values ?? []) scrubStacktrace(thread.stacktrace);
12875
13084
  for (const span of event.spans ?? []) scrubSpan(span);
12876
13085
  scrubSpan(event.contexts?.trace);
12877
- return event;
13086
+ return redactApiTokensDeep(event);
12878
13087
  }
12879
13088
  /**
12880
13089
  * Privacy options shared by `initCliTelemetry` and `initPublicSentry`.
@@ -13056,6 +13265,7 @@ function decodeAccessTokenSubject(token) {
13056
13265
  * from every other identity we already have for the same user.
13057
13266
  */
13058
13267
  function resolveProductAnalyticsDistinctId(scope) {
13268
+ if (isApiTokenMode()) return null;
13059
13269
  try {
13060
13270
  return decodeAccessTokenSubject(loadProfile(scope)?.access_token);
13061
13271
  } catch {
@@ -13156,7 +13366,7 @@ async function runSkillSetup(options) {
13156
13366
  });
13157
13367
  }
13158
13368
  //#endregion
13159
- //#region ../operations/build/validation-Byte2z0O.js
13369
+ //#region ../operations/build/validation-Cl22AQf7.js
13160
13370
  const optionalNumber = /* @__PURE__ */ optional$1(/* @__PURE__ */ number$2());
13161
13371
  const perPageField = (max) => /* @__PURE__ */ optional$1(/* @__PURE__ */ pipe$2(/* @__PURE__ */ number$2(), /* @__PURE__ */ integer(), /* @__PURE__ */ minValue$1(1), /* @__PURE__ */ maxValue$1(max), /* @__PURE__ */ description$1(`Results per page (1-${max})`)));
13162
13372
  const perPageSchema = perPageField(100);
@@ -14552,6 +14762,14 @@ const orgSharedOperations = [
14552
14762
  function operationRequiresExplicitAcknowledgment(operation) {
14553
14763
  return operation.destructive;
14554
14764
  }
14765
+ /**
14766
+ * `org` and `shared` operations call Toggl Accounts directly, and Accounts only
14767
+ * accepts OAuth/session credentials. With `TOGGL_API_TOKEN` they cannot work, so
14768
+ * both surfaces short-circuit them with a sign-in message instead of a 401.
14769
+ */
14770
+ function operationRequiresOAuth(operation) {
14771
+ return operation.family === "org" || operation.family === "shared";
14772
+ }
14555
14773
  const MAX_ERROR_LENGTH = 200;
14556
14774
  const MAX_RECEIVED_LENGTH = 40;
14557
14775
  function formatIssueMessage(issue) {
@@ -27929,6 +28147,17 @@ function filterRowsByQuerySlice(rows, query) {
27929
28147
  const q = query.trim().toLowerCase();
27930
28148
  return (q.length === 0 ? rows : rows.filter((r) => r.name.toLowerCase().includes(q) || (r.description?.toLowerCase().includes(q) ?? false) || String(r.value).includes(q))).slice(0, 25);
27931
28149
  }
28150
+ /** Pickers listed from Toggl Accounts, which rejects `TOGGL_API_TOKEN` keys. */
28151
+ const ACCOUNTS_BACKED_PICKERS = new Set(["org_workspace"]);
28152
+ /**
28153
+ * The picker to offer for a prompt path, or null for plain ID input. With an API key the
28154
+ * Accounts-backed pickers would only fail with a 401, so the prompt asks for IDs directly.
28155
+ */
28156
+ function usableEntityKindForPromptPath(path, env = process.env) {
28157
+ const kind = entityKindForPromptPath(path);
28158
+ if (kind && isApiTokenMode(env) && ACCOUNTS_BACKED_PICKERS.has(kind)) return null;
28159
+ return kind;
28160
+ }
27932
28161
  function entityKindForPromptPath(path) {
27933
28162
  const leaf = path.split(".").pop() ?? path;
27934
28163
  if (leaf === "project_id") return "project";
@@ -28243,7 +28472,7 @@ async function promptForField(field, adapter, entityContext) {
28243
28472
  default: false
28244
28473
  });
28245
28474
  if (field.type === "number") {
28246
- const entityKind = entityKindForPromptPath(field.path);
28475
+ const entityKind = usableEntityKindForPromptPath(field.path);
28247
28476
  if (entityContext && entityKind && adapter.searchNumber) {
28248
28477
  const source = createEntitySearchSource(entityKind, entityContext);
28249
28478
  const wrappedSource = async (term, opt) => {
@@ -28270,7 +28499,7 @@ async function promptForField(field, adapter, entityContext) {
28270
28499
  }
28271
28500
  if (field.type === "array") {
28272
28501
  if (field.itemSchema) return promptArrayOfObjectItems(field, adapter, entityContext);
28273
- const arrayEntityKind = field.itemType === "number" ? entityKindForPromptPath(field.path) : null;
28502
+ const arrayEntityKind = field.itemType === "number" ? usableEntityKindForPromptPath(field.path) : null;
28274
28503
  if (entityContext && arrayEntityKind) {
28275
28504
  let query;
28276
28505
  for (;;) {
@@ -28637,7 +28866,7 @@ async function runValidatedOperation(operation, options, deps) {
28637
28866
  return;
28638
28867
  }
28639
28868
  if (operationRequiresExplicitAcknowledgment(operation) && !options.yes) throw new Error(`${operation.id} is a destructive operation. Pass --yes to confirm, or --dry-run to preview.`);
28640
- const response = await operation.execute(input, { client: deps.getClient() });
28869
+ const response = await operation.execute(input, { client: await deps.getClient() });
28641
28870
  if (!response.ok) throw new Error(`${response.status}: ${response.message}`);
28642
28871
  deps.output(response.data);
28643
28872
  }
@@ -29015,7 +29244,68 @@ function outputJson(data, globalOptions) {
29015
29244
  if (globalOptions.json) process.stdout.write(JSON.stringify(data, null, 2) + "\n");
29016
29245
  else process.stdout.write(JSON.stringify(data, null, 2) + "\n");
29017
29246
  }
29018
- function getClient(options) {
29247
+ const CLI_API_TOKEN_PROFILES_MESSAGE = "Saved profiles are not used while TOGGL_API_TOKEN is set: every command authenticates with the API key. Unset TOGGL_API_TOKEN to use OAuth profiles again.";
29248
+ const CLI_API_TOKEN_WORKSPACE_MESSAGE = "While TOGGL_API_TOKEN is set the workspace comes from --workspace-id, TOGGL_WORKSPACE_ID and TOGGL_ORGANIZATION_ID (or your Toggl 2.0 current workspace).";
29249
+ /**
29250
+ * Resolves the API-key identity once per URL pair and `--workspace-id`, so a prompted
29251
+ * command (entity pickers, then the operation itself) does not repeat the probes.
29252
+ */
29253
+ function createCliApiTokenResolver(resolveUrls) {
29254
+ const caches = /* @__PURE__ */ new Map();
29255
+ function identity(options, urls = resolveUrls()) {
29256
+ const workspaceIdOverride = options.workspaceId ? parseWorkspaceIdArg(options.workspaceId) : void 0;
29257
+ const key = [
29258
+ urls.focusApiUrl,
29259
+ urls.accountsApiUrl,
29260
+ workspaceIdOverride ?? ""
29261
+ ].join("\n");
29262
+ let cache = caches.get(key);
29263
+ if (!cache) {
29264
+ cache = createApiTokenIdentityCache(() => ({
29265
+ focusApiUrl: urls.focusApiUrl,
29266
+ accountsApiUrl: urls.accountsApiUrl,
29267
+ clientSurface: "cli",
29268
+ workspaceIdOverride
29269
+ }));
29270
+ caches.set(key, cache);
29271
+ }
29272
+ return cache.resolve();
29273
+ }
29274
+ async function client(options) {
29275
+ const resolved = await identity(options);
29276
+ return new FocusClient({
29277
+ baseUrl: resolved.focus_api_url,
29278
+ accountsApiUrl: resolved.accounts_api_url,
29279
+ tokenProvider: () => getValidToken("cli"),
29280
+ userId: resolved.user_id,
29281
+ organizationId: String(resolved.organization_id),
29282
+ workspaceId: String(resolved.workspace_id),
29283
+ clientSurface: "cli"
29284
+ });
29285
+ }
29286
+ return {
29287
+ identity,
29288
+ client
29289
+ };
29290
+ }
29291
+ function describeCliApiTokenIdentity(identity) {
29292
+ return {
29293
+ auth_mode: "api_token",
29294
+ user_id: identity.user_id,
29295
+ organization_id: identity.organization_id,
29296
+ workspace_id: identity.workspace_id,
29297
+ focus_api_url: identity.focus_api_url,
29298
+ id_sources: identity.sources
29299
+ };
29300
+ }
29301
+ /** `org`/`shared` commands call Toggl Accounts, which rejects API keys. */
29302
+ function assertOperationAvailableInAuthMode(operation) {
29303
+ if (!isApiTokenMode() || !operationRequiresOAuth(operation)) return;
29304
+ const command = [...operation.cli.group, operation.cli.command].join(" ");
29305
+ throw new Error(oauthRequiredMessage(`\`toggl ${command}\``, "toggl auth"));
29306
+ }
29307
+ function getClient(options, apiToken) {
29308
+ if (isApiTokenMode()) return apiToken.client(options);
29019
29309
  const config = loadProfile("cli", options.profile);
29020
29310
  if (!config) throw new Error(`Not authenticated. Run \`toggl auth\` to sign in, or \`${npxMcpAuthCommand()}\` for a shared session.`);
29021
29311
  const urls = resolveEnvironmentUrls({
@@ -29032,10 +29322,10 @@ function getClient(options) {
29032
29322
  clientSurface: "cli"
29033
29323
  });
29034
29324
  }
29035
- async function runOperation(operation, globalOptions, options, rawInput) {
29325
+ async function runOperation(operation, globalOptions, options, apiToken, rawInput) {
29036
29326
  await runValidatedOperation(operation, options, {
29037
29327
  rawInput,
29038
- getClient: () => getClient(globalOptions),
29328
+ getClient: () => getClient(globalOptions, apiToken),
29039
29329
  output: (data) => output(data, globalOptions),
29040
29330
  outputJson: (data) => outputJson(data, globalOptions)
29041
29331
  });
@@ -29083,6 +29373,7 @@ function createProgram(programOptions = {}) {
29083
29373
  const promptAdapter = programOptions.promptAdapter ?? inquirerPromptAdapter;
29084
29374
  const isTty = programOptions.isTty ?? (() => Boolean(process.stdin.isTTY && process.stdout.isTTY));
29085
29375
  const env = programOptions.env ?? process.env;
29376
+ const apiToken = createCliApiTokenResolver(() => programOptions.resolveAuthUrls?.({}) ?? resolveEnvironmentUrls());
29086
29377
  const program = new Command();
29087
29378
  program.name("toggl").description("Toggl CLI — generated from the shared operation catalog").version(CLI_PACKAGE_VERSION).option("--json", "Output pretty-printed JSON").option("--profile <name>", "Use a saved auth profile").option("--workspace-id <id>", "Override the active workspace ID").exitOverride();
29088
29379
  const authCommand = program.command("auth").description("Authenticate with your Toggl account");
@@ -29090,6 +29381,12 @@ function createProgram(programOptions = {}) {
29090
29381
  authCommand.option("--workspace-id <id>", "Select a workspace by ID (required if you have multiple)").option("--profile <name>", "Profile name to save credentials under").option("--manual", "Headless/SSH flow: open the printed link, copy the code from accounts.toggl.com, paste here").option("--code <value>", "Authorization code from the login link (pair with --manual when not using localhost)").action(async (opts) => {
29091
29382
  try {
29092
29383
  const urls = programOptions.resolveAuthUrls?.(opts) ?? resolveEnvironmentUrls();
29384
+ if (isApiTokenMode()) {
29385
+ const identity = await apiToken.identity(program.opts(), urls);
29386
+ process.stderr.write("TOGGL_API_TOKEN is set, so no browser sign-in runs and no profile is saved.\n");
29387
+ output(describeCliApiTokenIdentity(identity), program.opts());
29388
+ return;
29389
+ }
29093
29390
  const globalOpts = program.opts();
29094
29391
  const workspaceId = opts.workspaceId ?? globalOpts.workspaceId;
29095
29392
  const profile = opts.profile ?? globalOpts.profile;
@@ -29128,6 +29425,17 @@ function createProgram(programOptions = {}) {
29128
29425
  workspaceCommand.command("list").description("Show workspaces you can use (active workspace is marked)").option("--refresh", "Re-fetch workspaces from your account").action(async (opts) => {
29129
29426
  try {
29130
29427
  const globalOptions = program.opts();
29428
+ if (isApiTokenMode()) {
29429
+ if (opts.refresh) throw new Error(oauthRequiredMessage("`toggl workspace list --refresh`", "toggl auth"));
29430
+ const identity = await apiToken.identity(globalOptions);
29431
+ output([{
29432
+ workspace_id: identity.workspace_id,
29433
+ organization_id: identity.organization_id,
29434
+ active: true,
29435
+ auth_mode: "api_token"
29436
+ }], globalOptions);
29437
+ return;
29438
+ }
29131
29439
  output(opts.refresh ? await refreshCliWorkspaces(globalOptions.profile) : listCachedCliWorkspaces(globalOptions.profile), globalOptions);
29132
29440
  } catch (error) {
29133
29441
  captureCliException(error);
@@ -29137,6 +29445,7 @@ function createProgram(programOptions = {}) {
29137
29445
  });
29138
29446
  workspaceCommand.command("switch").description("Set the active workspace ID used for Toggl 2.0 API calls").argument("[workspace-id]", "Workspace ID to activate (omit to choose interactively)").action(async (workspaceIdArg) => {
29139
29447
  try {
29448
+ if (isApiTokenMode()) throw new Error(CLI_API_TOKEN_WORKSPACE_MESSAGE);
29140
29449
  const globalOptions = program.opts();
29141
29450
  const target = switchCliWorkspace(await resolveWorkspaceIdOptional(workspaceIdArg, globalOptions, globalOptions.profile, {
29142
29451
  isTty,
@@ -29156,8 +29465,14 @@ function createProgram(programOptions = {}) {
29156
29465
  }
29157
29466
  });
29158
29467
  const profileCommand = program.command("profile").description("List, inspect, switch, or remove saved CLI profiles");
29159
- profileCommand.command("list").alias("ls").description("Show saved CLI profiles across environments").action(() => {
29468
+ profileCommand.command("list").alias("ls").description("Show saved CLI profiles across environments").action(async () => {
29160
29469
  try {
29470
+ if (isApiTokenMode()) {
29471
+ const identity = await apiToken.identity(program.opts());
29472
+ process.stderr.write(`${CLI_API_TOKEN_PROFILES_MESSAGE}\n`);
29473
+ output([describeCliApiTokenIdentity(identity)], program.opts());
29474
+ return;
29475
+ }
29161
29476
  output(listCliProfiles(), program.opts());
29162
29477
  } catch (error) {
29163
29478
  captureCliException(error);
@@ -29165,8 +29480,12 @@ function createProgram(programOptions = {}) {
29165
29480
  process.exitCode = 1;
29166
29481
  }
29167
29482
  });
29168
- profileCommand.command("current").description("Show the active CLI profile").action(() => {
29483
+ profileCommand.command("current").description("Show the active CLI profile").action(async () => {
29169
29484
  try {
29485
+ if (isApiTokenMode()) {
29486
+ output(describeCliApiTokenIdentity(await apiToken.identity(program.opts())), program.opts());
29487
+ return;
29488
+ }
29170
29489
  output(getCurrentCliProfile(), program.opts());
29171
29490
  } catch (error) {
29172
29491
  captureCliException(error);
@@ -29176,6 +29495,7 @@ function createProgram(programOptions = {}) {
29176
29495
  });
29177
29496
  profileCommand.command("switch").description("Set the active CLI profile").argument("[profile]", "Profile name to activate (omit to choose interactively)").action(async (profileArg) => {
29178
29497
  try {
29498
+ if (isApiTokenMode()) throw new Error(CLI_API_TOKEN_PROFILES_MESSAGE);
29179
29499
  const globalOptions = program.opts();
29180
29500
  output(switchCliProfile(await resolveCliProfileNameOptional(profileArg, globalOptions, {
29181
29501
  isTty,
@@ -29190,6 +29510,7 @@ function createProgram(programOptions = {}) {
29190
29510
  });
29191
29511
  profileCommand.command("remove").description("Remove a saved CLI profile").argument("[profile]", "Profile name to remove (omit to choose interactively)").action(async (profileArg) => {
29192
29512
  try {
29513
+ if (isApiTokenMode()) throw new Error(CLI_API_TOKEN_PROFILES_MESSAGE);
29193
29514
  const globalOptions = program.opts();
29194
29515
  output(removeCliProfile(await resolveCliProfileNameOptional(profileArg, globalOptions, {
29195
29516
  isTty,
@@ -29249,6 +29570,7 @@ Common commands:
29249
29570
  if (operationRequiresExplicitAcknowledgment(operation)) command.option("--yes", "Confirm destructive operation without prompting");
29250
29571
  command.action(async (cmdOptions) => {
29251
29572
  try {
29573
+ assertOperationAvailableInAuthMode(operation);
29252
29574
  const globalOptions = program.opts();
29253
29575
  const explicitInput = hasExplicitInput(operation, cmdOptions);
29254
29576
  const rawInput = await readInput(operation, cmdOptions);
@@ -29260,8 +29582,8 @@ Common commands:
29260
29582
  isTty: isTty(),
29261
29583
  env
29262
29584
  });
29263
- const entityContext = willPrompt && !cmdOptions.dryRun ? { client: getClient(globalOptions) } : void 0;
29264
- await runOperation(operation, globalOptions, cmdOptions, willPrompt ? await promptForOperationInput(operation, rawInput, promptAdapter, entityContext) : rawInput);
29585
+ const entityContext = willPrompt && !cmdOptions.dryRun ? { client: await getClient(globalOptions, apiToken) } : void 0;
29586
+ await runOperation(operation, globalOptions, cmdOptions, apiToken, willPrompt ? await promptForOperationInput(operation, rawInput, promptAdapter, entityContext) : rawInput);
29265
29587
  } catch (error) {
29266
29588
  captureCliException(error);
29267
29589
  process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
@@ -29292,4 +29614,4 @@ Common commands:
29292
29614
  //#endregion
29293
29615
  export { CommanderError as a, shutdownCliTelemetry as i, captureCliException as n, initCliTelemetry as r, createProgram as t };
29294
29616
 
29295
- //# sourceMappingURL=program-BB9t7xvO.js.map
29617
+ //# sourceMappingURL=program-BLPqhZj7.js.map
@@ -978,5 +978,5 @@ interface CreateProgramOptions {
978
978
  }
979
979
  declare function createProgram(programOptions?: CreateProgramOptions): Command;
980
980
  //#endregion
981
- export { createProgram as t };
982
- //# sourceMappingURL=program-Bby4U_hT.d.ts.map
981
+ export { createProgram as n, CreateProgramOptions as t };
982
+ //# sourceMappingURL=program-CxOdqdfD.d.ts.map
@@ -1,2 +1,2 @@
1
- import { t as createProgram } from "./program-Bby4U_hT.js";
2
- export { createProgram };
1
+ import { n as createProgram, t as CreateProgramOptions } from "./program-CxOdqdfD.js";
2
+ export { CreateProgramOptions, createProgram };
package/build/program.js CHANGED
@@ -1,2 +1,2 @@
1
- import { t as createProgram } from "./program-BB9t7xvO.js";
1
+ import { t as createProgram } from "./program-BLPqhZj7.js";
2
2
  export { createProgram };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@togglhq/cli",
3
- "version": "1.11.226",
3
+ "version": "1.12.0",
4
4
  "description": "Toggl CLI for Toggl 2.0 API operations.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",