@togglhq/cli 1.5.19 → 1.5.21
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/LICENSE +6 -0
- package/README.md +8 -12
- package/build/index.js +1 -1
- package/build/{program-BwnVUFVS.js → program-Bz9wasNE.js} +119 -117
- package/build/program.js +1 -1
- package/package.json +4 -7
- package/skills/toggl-cli/INTERNAL.md +11 -0
- package/skills/toggl-cli/SKILL.md +7 -7
- package/skills/toggl-cli/reference/auth-environments-workspaces.md +1 -1
- package/skills/toggl-cli/reference/focus-concepts.md +5 -5
- package/skills/toggl-cli/reference/projects.md +1 -1
- package/skills/toggl-cli/reference/rates-and-billables.md +4 -4
- package/skills/toggl-cli/reference/tasks.md +1 -1
- package/skills/toggl-cli/reference/time-blocks.md +1 -1
package/LICENSE
ADDED
package/README.md
CHANGED
|
@@ -1,21 +1,13 @@
|
|
|
1
1
|
# @toggl/cli
|
|
2
2
|
|
|
3
|
-
Command-line interface for [Toggl
|
|
3
|
+
Command-line interface for [Toggl 2.0](https://focus.toggl.com).
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
|
-
From npm (no GitHub token):
|
|
8
|
-
|
|
9
7
|
```bash
|
|
10
8
|
npm install -g @togglhq/cli
|
|
11
9
|
```
|
|
12
10
|
|
|
13
|
-
Or from GitHub Packages (Toggl staff): configure your `.npmrc` with a GitHub Packages token, then:
|
|
14
|
-
|
|
15
|
-
```bash
|
|
16
|
-
npm install -g @toggl/cli-internal
|
|
17
|
-
```
|
|
18
|
-
|
|
19
11
|
Or run without installing:
|
|
20
12
|
|
|
21
13
|
```bash
|
|
@@ -55,13 +47,13 @@ The active profile controls both the account and environment for later commands.
|
|
|
55
47
|
|
|
56
48
|
## Agent skill setup
|
|
57
49
|
|
|
58
|
-
`@
|
|
50
|
+
`@togglhq/cli` ships a `toggl-cli` agent skill under `skills/toggl-cli`. Install it with:
|
|
59
51
|
|
|
60
52
|
```bash
|
|
61
53
|
toggl skill setup
|
|
62
54
|
```
|
|
63
55
|
|
|
64
|
-
This delegates to the [`skills`](https://www.npmjs.com/package/skills) CLI, listed as a **dependency** of `@
|
|
56
|
+
This delegates to the [`skills`](https://www.npmjs.com/package/skills) CLI, listed as a **dependency** of `@togglhq/cli` (no separate install). Interactive agent/scope prompts come from that CLI.
|
|
65
57
|
|
|
66
58
|
After upgrading the CLI, refresh the skill install:
|
|
67
59
|
|
|
@@ -78,7 +70,7 @@ toggl skill setup --agent cursor codex --copy --yes
|
|
|
78
70
|
|
|
79
71
|
## Command shape
|
|
80
72
|
|
|
81
|
-
Generated
|
|
73
|
+
Generated Toggl 2.0 commands look like:
|
|
82
74
|
|
|
83
75
|
```
|
|
84
76
|
toggl [global flags] <group> … <subcommand> [flags]
|
|
@@ -297,3 +289,7 @@ TOGGL_DEBUG=1 toggl tasks list
|
|
|
297
289
|
```
|
|
298
290
|
|
|
299
291
|
Prints schema validation warnings from API responses to stderr.
|
|
292
|
+
|
|
293
|
+
## License
|
|
294
|
+
|
|
295
|
+
Proprietary Toggl software. See [LICENSE](LICENSE) and [Toggl legal terms](https://toggl.com/legal/).
|
package/build/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { n as CommanderError, t as createProgram } from "./program-
|
|
2
|
+
import { n as CommanderError, t as createProgram } from "./program-Bz9wasNE.js";
|
|
3
3
|
//#region src/index.ts
|
|
4
4
|
try {
|
|
5
5
|
await createProgram({ enableUpdateNotification: true }).parseAsync(process.argv);
|
|
@@ -2,7 +2,7 @@ import { createRequire } from "node:module";
|
|
|
2
2
|
import { exec, spawn } from "node:child_process";
|
|
3
3
|
import * as path$1 from "node:path";
|
|
4
4
|
import path, { basename, dirname, extname, join } from "node:path";
|
|
5
|
-
import * as fs from "node:fs";
|
|
5
|
+
import * as fs$1 from "node:fs";
|
|
6
6
|
import { readFileSync } from "node:fs";
|
|
7
7
|
import process$1 from "node:process";
|
|
8
8
|
import { fileURLToPath } from "node:url";
|
|
@@ -11,7 +11,7 @@ import { stripVTControlCharacters, styleText } from "node:util";
|
|
|
11
11
|
import * as readline from "node:readline";
|
|
12
12
|
import * as os from "node:os";
|
|
13
13
|
import * as crypto from "node:crypto";
|
|
14
|
-
import * as fs
|
|
14
|
+
import * as fs from "node:fs/promises";
|
|
15
15
|
import { mkdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
16
16
|
import { createInterface } from "node:readline/promises";
|
|
17
17
|
import * as http from "node:http";
|
|
@@ -5203,82 +5203,14 @@ var dist_default = createPrompt((config, done) => {
|
|
|
5203
5203
|
].filter(Boolean).join("\n").trimEnd()}${cursorHide}`;
|
|
5204
5204
|
});
|
|
5205
5205
|
//#endregion
|
|
5206
|
-
//#region src/skill-setup.ts
|
|
5207
|
-
function resolveSkillsCliBinImportMeta(metaUrl) {
|
|
5208
|
-
const resolveFn = import.meta.resolve;
|
|
5209
|
-
if (typeof resolveFn !== "function") return;
|
|
5210
|
-
try {
|
|
5211
|
-
return fileURLToPath(resolveFn("skills/bin/cli.mjs", metaUrl));
|
|
5212
|
-
} catch {
|
|
5213
|
-
return;
|
|
5214
|
-
}
|
|
5215
|
-
}
|
|
5216
|
-
function resolveSkillsCliBinRequire(metaUrl, packageRoot) {
|
|
5217
|
-
try {
|
|
5218
|
-
return createRequire(metaUrl).resolve("skills/bin/cli.mjs", { paths: [packageRoot] });
|
|
5219
|
-
} catch {
|
|
5220
|
-
return;
|
|
5221
|
-
}
|
|
5222
|
-
}
|
|
5223
|
-
const TOGGL_CLI_SKILL_NAME = "toggl-cli";
|
|
5224
|
-
function buildSkillsAddArgs(packageRoot, options) {
|
|
5225
|
-
const args = [
|
|
5226
|
-
"add",
|
|
5227
|
-
packageRoot,
|
|
5228
|
-
"--skill",
|
|
5229
|
-
TOGGL_CLI_SKILL_NAME
|
|
5230
|
-
];
|
|
5231
|
-
const agents = typeof options.agent === "string" ? [options.agent] : options.agent;
|
|
5232
|
-
if (agents?.length) args.push("--agent", ...agents);
|
|
5233
|
-
if (options.global) args.push("--global");
|
|
5234
|
-
if (options.copy) args.push("--copy");
|
|
5235
|
-
if (options.yes) args.push("--yes");
|
|
5236
|
-
return args;
|
|
5237
|
-
}
|
|
5238
|
-
function resolveCliPackageRoot(metaUrl = import.meta.url) {
|
|
5239
|
-
return fileURLToPath(new URL("..", metaUrl));
|
|
5240
|
-
}
|
|
5241
|
-
function resolveSkillsCliBin(metaUrl = import.meta.url) {
|
|
5242
|
-
const packageRoot = resolveCliPackageRoot(metaUrl);
|
|
5243
|
-
const legacyBundled = path$1.join(packageRoot, "bundled", "skills-runtime", "node_modules", "skills", "bin", "cli.mjs");
|
|
5244
|
-
return resolveSkillsCliBinImportMeta(metaUrl) ?? resolveSkillsCliBinRequire(metaUrl, packageRoot) ?? legacyBundled;
|
|
5245
|
-
}
|
|
5246
|
-
async function assertBundledSkillExists(packageRoot) {
|
|
5247
|
-
const skillPath = path$1.join(packageRoot, "skills", TOGGL_CLI_SKILL_NAME, "SKILL.md");
|
|
5248
|
-
await fs$1.access(skillPath);
|
|
5249
|
-
}
|
|
5250
|
-
async function runSkillSetup(options) {
|
|
5251
|
-
const packageRoot = resolveCliPackageRoot();
|
|
5252
|
-
await assertBundledSkillExists(packageRoot);
|
|
5253
|
-
const skillsBin = resolveSkillsCliBin();
|
|
5254
|
-
try {
|
|
5255
|
-
await fs$1.access(skillsBin);
|
|
5256
|
-
} catch {
|
|
5257
|
-
throw new Error(`Could not find the skills installer at ${skillsBin}. Reinstall @toggl/cli.`);
|
|
5258
|
-
}
|
|
5259
|
-
const args = buildSkillsAddArgs(packageRoot, options);
|
|
5260
|
-
await new Promise((resolve, reject) => {
|
|
5261
|
-
const child = spawn(process.execPath, [skillsBin, ...args], { stdio: "inherit" });
|
|
5262
|
-
child.on("error", reject);
|
|
5263
|
-
child.on("exit", (code, signal) => {
|
|
5264
|
-
if (code === 0) {
|
|
5265
|
-
resolve();
|
|
5266
|
-
return;
|
|
5267
|
-
}
|
|
5268
|
-
const reason = signal ? `signal ${signal}` : `exit code ${code ?? "unknown"}`;
|
|
5269
|
-
reject(/* @__PURE__ */ new Error(`skills ${args.join(" ")} failed with ${reason}`));
|
|
5270
|
-
});
|
|
5271
|
-
});
|
|
5272
|
-
}
|
|
5273
|
-
//#endregion
|
|
5274
5206
|
//#region ../cli-core/build/profile-Empu4JWK.js
|
|
5275
5207
|
const CONFIG_DIR = path$1.join(os.homedir(), ".toggl");
|
|
5276
5208
|
const CONFIG_FILE = path$1.join(CONFIG_DIR, "focus-tools.json");
|
|
5277
5209
|
const LEGACY_MCP_CONFIG_FILE = path$1.join(os.homedir(), ".toggl-focus-mcp", "config.json");
|
|
5278
5210
|
function readJsonFile(filePath) {
|
|
5279
|
-
if (!fs.existsSync(filePath)) return null;
|
|
5211
|
+
if (!fs$1.existsSync(filePath)) return null;
|
|
5280
5212
|
try {
|
|
5281
|
-
return JSON.parse(fs.readFileSync(filePath, "utf-8"));
|
|
5213
|
+
return JSON.parse(fs$1.readFileSync(filePath, "utf-8"));
|
|
5282
5214
|
} catch (err) {
|
|
5283
5215
|
const msg = err instanceof Error ? err.message : String(err);
|
|
5284
5216
|
throw new Error(`Failed to read ${filePath}: ${msg}`, { cause: err });
|
|
@@ -5286,10 +5218,10 @@ function readJsonFile(filePath) {
|
|
|
5286
5218
|
}
|
|
5287
5219
|
function saveLegacyAuthConfig(config) {
|
|
5288
5220
|
const dir = path$1.dirname(LEGACY_MCP_CONFIG_FILE);
|
|
5289
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
5221
|
+
fs$1.mkdirSync(dir, { recursive: true });
|
|
5290
5222
|
const tmp = `${LEGACY_MCP_CONFIG_FILE}.${process.pid}.tmp`;
|
|
5291
|
-
fs.writeFileSync(tmp, JSON.stringify(config, null, 2) + "\n", { mode: 384 });
|
|
5292
|
-
fs.renameSync(tmp, LEGACY_MCP_CONFIG_FILE);
|
|
5223
|
+
fs$1.writeFileSync(tmp, JSON.stringify(config, null, 2) + "\n", { mode: 384 });
|
|
5224
|
+
fs$1.renameSync(tmp, LEGACY_MCP_CONFIG_FILE);
|
|
5293
5225
|
}
|
|
5294
5226
|
function loadDeveloperToolsConfig() {
|
|
5295
5227
|
const config = readJsonFile(CONFIG_FILE);
|
|
@@ -5307,10 +5239,10 @@ function loadProfile(scope = "cli", profile) {
|
|
|
5307
5239
|
return legacy;
|
|
5308
5240
|
}
|
|
5309
5241
|
function saveDeveloperToolsConfig(config) {
|
|
5310
|
-
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
5242
|
+
fs$1.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
5311
5243
|
const tmp = `${CONFIG_FILE}.${process.pid}.tmp`;
|
|
5312
|
-
fs.writeFileSync(tmp, JSON.stringify(config, null, 2) + "\n", { mode: 384 });
|
|
5313
|
-
fs.renameSync(tmp, CONFIG_FILE);
|
|
5244
|
+
fs$1.writeFileSync(tmp, JSON.stringify(config, null, 2) + "\n", { mode: 384 });
|
|
5245
|
+
fs$1.renameSync(tmp, CONFIG_FILE);
|
|
5314
5246
|
}
|
|
5315
5247
|
function profileEnvironment(focusApiUrl) {
|
|
5316
5248
|
const hostname = new URL(focusApiUrl).hostname;
|
|
@@ -12204,7 +12136,7 @@ async function fetchAccessibleWorkspaces(accountsApiUrl, token) {
|
|
|
12204
12136
|
}));
|
|
12205
12137
|
}
|
|
12206
12138
|
async function resolveAuthenticatedWorkspace(workspaces, options) {
|
|
12207
|
-
if (workspaces.length === 0) throw new Error("No
|
|
12139
|
+
if (workspaces.length === 0) throw new Error("No Toggl 2.0 workspaces found for this account.");
|
|
12208
12140
|
if (options.explicitWorkspaceId !== void 0) {
|
|
12209
12141
|
const match = workspaces.find((w) => w.workspace_id === options.explicitWorkspaceId);
|
|
12210
12142
|
if (!match) throw new Error(`Workspace ${options.explicitWorkspaceId} not found. Available: ${workspaces.map((w) => `${w.workspace_id} (${w.workspace_name})`).join(", ")}`);
|
|
@@ -12282,6 +12214,13 @@ async function runCliAuthFlow(options = {}) {
|
|
|
12282
12214
|
log(`Profile saved as '${profileName}' in ~/.toggl/focus-tools.json`);
|
|
12283
12215
|
return config;
|
|
12284
12216
|
}
|
|
12217
|
+
const PUBLIC_CLI_PACKAGE_NAME = "@togglhq/cli";
|
|
12218
|
+
const PUBLIC_MCP_PACKAGE_NAME = "@togglhq/mcp";
|
|
12219
|
+
const PUBLIC_CLI_PACKAGE_SPEC = `${PUBLIC_CLI_PACKAGE_NAME}@latest`;
|
|
12220
|
+
`${PUBLIC_MCP_PACKAGE_NAME}`;
|
|
12221
|
+
function npxMcpAuthCommand() {
|
|
12222
|
+
return `npx ${PUBLIC_MCP_PACKAGE_NAME} auth`;
|
|
12223
|
+
}
|
|
12285
12224
|
async function refreshTokens(accountsApiUrl, refreshToken) {
|
|
12286
12225
|
const params = new URLSearchParams({
|
|
12287
12226
|
grant_type: "refresh_token",
|
|
@@ -12297,7 +12236,7 @@ async function refreshTokens(accountsApiUrl, refreshToken) {
|
|
|
12297
12236
|
}
|
|
12298
12237
|
async function getValidToken(scope = "cli", profile) {
|
|
12299
12238
|
const authConfig = loadProfile(scope, profile);
|
|
12300
|
-
if (!authConfig) throw new Error(scope === "cli" ? "Not authenticated. Run `toggl auth` to sign in." :
|
|
12239
|
+
if (!authConfig) throw new Error(scope === "cli" ? "Not authenticated. Run `toggl auth` to sign in." : `Not authenticated. Run \`${npxMcpAuthCommand()}\` to sign in.`);
|
|
12301
12240
|
const now = Date.now() / 1e3;
|
|
12302
12241
|
if (authConfig.expires_at > now + 60) return authConfig.access_token;
|
|
12303
12242
|
const tokens = await refreshTokens(authConfig.accounts_api_url, authConfig.refresh_token);
|
|
@@ -12309,7 +12248,7 @@ async function getValidToken(scope = "cli", profile) {
|
|
|
12309
12248
|
if (developerConfig && activeProfile && developerConfig.profiles[activeProfile]) {
|
|
12310
12249
|
developerConfig.profiles[activeProfile] = authConfig;
|
|
12311
12250
|
saveDeveloperToolsConfig(developerConfig);
|
|
12312
|
-
} else if (fs.existsSync(LEGACY_MCP_CONFIG_FILE)) saveLegacyAuthConfig(authConfig);
|
|
12251
|
+
} else if (fs$1.existsSync(LEGACY_MCP_CONFIG_FILE)) saveLegacyAuthConfig(authConfig);
|
|
12313
12252
|
return authConfig.access_token;
|
|
12314
12253
|
}
|
|
12315
12254
|
function requireCliDeveloperProfile(profile) {
|
|
@@ -12358,6 +12297,99 @@ function switchCliWorkspace(workspaceId, profile) {
|
|
|
12358
12297
|
return target;
|
|
12359
12298
|
}
|
|
12360
12299
|
//#endregion
|
|
12300
|
+
//#region src/cli-package-manifest.ts
|
|
12301
|
+
const pkgJsonPath = path$1.join(path$1.dirname(fileURLToPath(import.meta.url)), "..", "package.json");
|
|
12302
|
+
function getPublicPackageName() {
|
|
12303
|
+
return PUBLIC_CLI_PACKAGE_NAME;
|
|
12304
|
+
}
|
|
12305
|
+
function getPublicPackageSpec() {
|
|
12306
|
+
return PUBLIC_CLI_PACKAGE_SPEC;
|
|
12307
|
+
}
|
|
12308
|
+
getPublicPackageName();
|
|
12309
|
+
getPublicPackageSpec();
|
|
12310
|
+
async function readCliPackageManifest() {
|
|
12311
|
+
const raw = await readFile(pkgJsonPath, "utf-8");
|
|
12312
|
+
return JSON.parse(raw);
|
|
12313
|
+
}
|
|
12314
|
+
async function readCliPackageVersion() {
|
|
12315
|
+
const parsed = await readCliPackageManifest();
|
|
12316
|
+
if (!parsed.version) throw new Error("Missing version in package.json");
|
|
12317
|
+
return parsed.version;
|
|
12318
|
+
}
|
|
12319
|
+
function isRunningViaNpx() {
|
|
12320
|
+
if (process.env.NPX_CLI_JS) return true;
|
|
12321
|
+
const argv1 = process.argv[1] ?? "";
|
|
12322
|
+
return argv1.includes("_npx") || /[/\\]npx[/\\]/.test(argv1);
|
|
12323
|
+
}
|
|
12324
|
+
//#endregion
|
|
12325
|
+
//#region src/skill-setup.ts
|
|
12326
|
+
function resolveSkillsCliBinImportMeta(metaUrl) {
|
|
12327
|
+
const resolveFn = import.meta.resolve;
|
|
12328
|
+
if (typeof resolveFn !== "function") return;
|
|
12329
|
+
try {
|
|
12330
|
+
return fileURLToPath(resolveFn("skills/bin/cli.mjs", metaUrl));
|
|
12331
|
+
} catch {
|
|
12332
|
+
return;
|
|
12333
|
+
}
|
|
12334
|
+
}
|
|
12335
|
+
function resolveSkillsCliBinRequire(metaUrl, packageRoot) {
|
|
12336
|
+
try {
|
|
12337
|
+
return createRequire(metaUrl).resolve("skills/bin/cli.mjs", { paths: [packageRoot] });
|
|
12338
|
+
} catch {
|
|
12339
|
+
return;
|
|
12340
|
+
}
|
|
12341
|
+
}
|
|
12342
|
+
const TOGGL_CLI_SKILL_NAME = "toggl-cli";
|
|
12343
|
+
function buildSkillsAddArgs(packageRoot, options) {
|
|
12344
|
+
const args = [
|
|
12345
|
+
"add",
|
|
12346
|
+
packageRoot,
|
|
12347
|
+
"--skill",
|
|
12348
|
+
TOGGL_CLI_SKILL_NAME
|
|
12349
|
+
];
|
|
12350
|
+
const agents = typeof options.agent === "string" ? [options.agent] : options.agent;
|
|
12351
|
+
if (agents?.length) args.push("--agent", ...agents);
|
|
12352
|
+
if (options.global) args.push("--global");
|
|
12353
|
+
if (options.copy) args.push("--copy");
|
|
12354
|
+
if (options.yes) args.push("--yes");
|
|
12355
|
+
return args;
|
|
12356
|
+
}
|
|
12357
|
+
function resolveCliPackageRoot(metaUrl = import.meta.url) {
|
|
12358
|
+
return fileURLToPath(new URL("..", metaUrl));
|
|
12359
|
+
}
|
|
12360
|
+
function resolveSkillsCliBin(metaUrl = import.meta.url) {
|
|
12361
|
+
const packageRoot = resolveCliPackageRoot(metaUrl);
|
|
12362
|
+
const legacyBundled = path$1.join(packageRoot, "bundled", "skills-runtime", "node_modules", "skills", "bin", "cli.mjs");
|
|
12363
|
+
return resolveSkillsCliBinImportMeta(metaUrl) ?? resolveSkillsCliBinRequire(metaUrl, packageRoot) ?? legacyBundled;
|
|
12364
|
+
}
|
|
12365
|
+
async function assertBundledSkillExists(packageRoot) {
|
|
12366
|
+
const skillPath = path$1.join(packageRoot, "skills", TOGGL_CLI_SKILL_NAME, "SKILL.md");
|
|
12367
|
+
await fs.access(skillPath);
|
|
12368
|
+
}
|
|
12369
|
+
async function runSkillSetup(options) {
|
|
12370
|
+
const packageRoot = resolveCliPackageRoot();
|
|
12371
|
+
await assertBundledSkillExists(packageRoot);
|
|
12372
|
+
const skillsBin = resolveSkillsCliBin();
|
|
12373
|
+
try {
|
|
12374
|
+
await fs.access(skillsBin);
|
|
12375
|
+
} catch {
|
|
12376
|
+
throw new Error(`Could not find the skills installer at ${skillsBin}. Reinstall ${getPublicPackageName()}.`);
|
|
12377
|
+
}
|
|
12378
|
+
const args = buildSkillsAddArgs(packageRoot, options);
|
|
12379
|
+
await new Promise((resolve, reject) => {
|
|
12380
|
+
const child = spawn(process.execPath, [skillsBin, ...args], { stdio: "inherit" });
|
|
12381
|
+
child.on("error", reject);
|
|
12382
|
+
child.on("exit", (code, signal) => {
|
|
12383
|
+
if (code === 0) {
|
|
12384
|
+
resolve();
|
|
12385
|
+
return;
|
|
12386
|
+
}
|
|
12387
|
+
const reason = signal ? `signal ${signal}` : `exit code ${code ?? "unknown"}`;
|
|
12388
|
+
reject(/* @__PURE__ */ new Error(`skills ${args.join(" ")} failed with ${reason}`));
|
|
12389
|
+
});
|
|
12390
|
+
});
|
|
12391
|
+
}
|
|
12392
|
+
//#endregion
|
|
12361
12393
|
//#region ../focus-queries/dist/attachments/requests.ts
|
|
12362
12394
|
async function getWorkspaceAttachmentStorage(httpClient, organization_id, workspace_id, signal) {
|
|
12363
12395
|
return await httpClient.get(`organizations/${organization_id}/workspaces/${workspace_id}/attachments/storage`, { signal }).json();
|
|
@@ -23856,7 +23888,7 @@ const schedulerOverrides = {
|
|
|
23856
23888
|
"focus.scheduler.validate-instructions": { hidden: true }
|
|
23857
23889
|
};
|
|
23858
23890
|
const searchOverrides = { "focus.search.search": {
|
|
23859
|
-
description: "Search across
|
|
23891
|
+
description: "Search across Toggl 2.0 entities.",
|
|
23860
23892
|
cli: {
|
|
23861
23893
|
group: [],
|
|
23862
23894
|
command: "search",
|
|
@@ -25464,7 +25496,7 @@ function inputFromScalarFlags(operation, options) {
|
|
|
25464
25496
|
return hasAny ? result : void 0;
|
|
25465
25497
|
}
|
|
25466
25498
|
async function readInput(operation, options) {
|
|
25467
|
-
if (options.dataFile) return parseJson(await fs
|
|
25499
|
+
if (options.dataFile) return parseJson(await fs.readFile(options.dataFile, "utf-8"), options.dataFile);
|
|
25468
25500
|
if (options.data === "-") return parseJson(await readStdin(), "stdin");
|
|
25469
25501
|
if (options.data) return parseJson(options.data, "--data");
|
|
25470
25502
|
const fromFlags = inputFromScalarFlags(operation, options);
|
|
@@ -25555,36 +25587,6 @@ function formatHumanOutput(data) {
|
|
|
25555
25587
|
return `${formatValue(data)}\n`;
|
|
25556
25588
|
}
|
|
25557
25589
|
//#endregion
|
|
25558
|
-
//#region src/cli-package-manifest.ts
|
|
25559
|
-
const PUBLIC_PACKAGE_FALLBACK = "@togglhq/cli";
|
|
25560
|
-
const pkgJsonPath = path$1.join(path$1.dirname(fileURLToPath(import.meta.url)), "..", "package.json");
|
|
25561
|
-
function getPublicPackageName() {
|
|
25562
|
-
try {
|
|
25563
|
-
return JSON.parse(readFileSync(pkgJsonPath, "utf-8")).name ?? "@togglhq/cli";
|
|
25564
|
-
} catch {
|
|
25565
|
-
return PUBLIC_PACKAGE_FALLBACK;
|
|
25566
|
-
}
|
|
25567
|
-
}
|
|
25568
|
-
function getPublicPackageSpec() {
|
|
25569
|
-
return `${getPublicPackageName()}@latest`;
|
|
25570
|
-
}
|
|
25571
|
-
getPublicPackageName();
|
|
25572
|
-
getPublicPackageSpec();
|
|
25573
|
-
async function readCliPackageManifest() {
|
|
25574
|
-
const raw = await readFile(pkgJsonPath, "utf-8");
|
|
25575
|
-
return JSON.parse(raw);
|
|
25576
|
-
}
|
|
25577
|
-
async function readCliPackageVersion() {
|
|
25578
|
-
const parsed = await readCliPackageManifest();
|
|
25579
|
-
if (!parsed.version) throw new Error("Missing version in package.json");
|
|
25580
|
-
return parsed.version;
|
|
25581
|
-
}
|
|
25582
|
-
function isRunningViaNpx() {
|
|
25583
|
-
if (process.env.NPX_CLI_JS) return true;
|
|
25584
|
-
const argv1 = process.argv[1] ?? "";
|
|
25585
|
-
return argv1.includes("_npx") || /[/\\]npx[/\\]/.test(argv1);
|
|
25586
|
-
}
|
|
25587
|
-
//#endregion
|
|
25588
25590
|
//#region src/update-notification.ts
|
|
25589
25591
|
const UPDATE_CHECK_CACHE_FILE = path$1.join(CONFIG_DIR, "cli-update-check.json");
|
|
25590
25592
|
const CACHE_TTL_MS = 1440 * 60 * 1e3;
|
|
@@ -25833,7 +25835,7 @@ function outputJson(data, globalOptions) {
|
|
|
25833
25835
|
}
|
|
25834
25836
|
function getClient(options) {
|
|
25835
25837
|
const config = loadProfile("cli", options.profile);
|
|
25836
|
-
if (!config) throw new Error(
|
|
25838
|
+
if (!config) throw new Error(`Not authenticated. Run \`toggl auth\` to sign in, or \`${npxMcpAuthCommand()}\` for a shared session.`);
|
|
25837
25839
|
const urls = resolveEnvironmentUrls({
|
|
25838
25840
|
focusApiUrl: config.focus_api_url,
|
|
25839
25841
|
accountsApiUrl: coalesceAccountsApiUrl(config.focus_api_url, config.accounts_api_url)
|
|
@@ -25934,7 +25936,7 @@ function createProgram(programOptions = {}) {
|
|
|
25934
25936
|
process.exitCode = 1;
|
|
25935
25937
|
}
|
|
25936
25938
|
});
|
|
25937
|
-
workspaceCommand.command("switch").description("Set the active workspace ID used for
|
|
25939
|
+
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) => {
|
|
25938
25940
|
try {
|
|
25939
25941
|
const globalOptions = program.opts();
|
|
25940
25942
|
const target = switchCliWorkspace(await resolveWorkspaceIdOptional(workspaceIdArg, globalOptions, globalOptions.profile, {
|
|
@@ -26022,7 +26024,7 @@ function createProgram(programOptions = {}) {
|
|
|
26022
26024
|
});
|
|
26023
26025
|
}
|
|
26024
26026
|
registerSkillInstall("setup", ["add"], "Install the packaged toggl-cli skill via the skills CLI (default: symlink so updates track CLI upgrades)");
|
|
26025
|
-
registerSkillInstall("sync", ["update"],
|
|
26027
|
+
registerSkillInstall("sync", ["update"], `Re-install the toggl-cli skill from this CLI package (run after upgrading ${getPublicPackageName()})`);
|
|
26026
26028
|
program.addHelpText("after", `
|
|
26027
26029
|
Common commands:
|
|
26028
26030
|
toggl auth Sign in with your Toggl account
|
|
@@ -26080,4 +26082,4 @@ Common commands:
|
|
|
26080
26082
|
//#endregion
|
|
26081
26083
|
export { CommanderError as n, createProgram as t };
|
|
26082
26084
|
|
|
26083
|
-
//# sourceMappingURL=program-
|
|
26085
|
+
//# sourceMappingURL=program-Bz9wasNE.js.map
|
package/build/program.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as createProgram } from "./program-
|
|
1
|
+
import { t as createProgram } from "./program-Bz9wasNE.js";
|
|
2
2
|
export { createProgram };
|
package/package.json
CHANGED
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@togglhq/cli",
|
|
3
|
-
"version": "1.5.
|
|
4
|
-
"description": "Toggl CLI for
|
|
3
|
+
"version": "1.5.21",
|
|
4
|
+
"description": "Toggl CLI for Toggl 2.0 API operations.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
|
-
"repository": {
|
|
7
|
-
"type": "git",
|
|
8
|
-
"url": "https://github.com/toggl/toggl-mcp.git"
|
|
9
|
-
},
|
|
10
6
|
"type": "module",
|
|
11
7
|
"publishConfig": {
|
|
12
8
|
"registry": "https://registry.npmjs.org",
|
|
@@ -31,7 +27,8 @@
|
|
|
31
27
|
"build/**/*.js",
|
|
32
28
|
"build/**/*.d.ts",
|
|
33
29
|
"skills/**",
|
|
34
|
-
"README.md"
|
|
30
|
+
"README.md",
|
|
31
|
+
"LICENSE"
|
|
35
32
|
],
|
|
36
33
|
"scripts": {
|
|
37
34
|
"build": "tsdown",
|
|
@@ -2,6 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
Install `@toggl/cli-internal` from **GitHub Packages** for internal builds that include staging and MS environment helpers (`toggl-internal` bin).
|
|
4
4
|
|
|
5
|
+
Configure `~/.npmrc` with a GitHub Packages token (`read:packages`) and Toggl org access:
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
@toggl:registry=https://npm.pkg.github.com/
|
|
9
|
+
//npm.pkg.github.com/:_authToken=<GH_NPM_TOKEN>
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install -g @toggl/cli-internal
|
|
14
|
+
```
|
|
15
|
+
|
|
5
16
|
## Environments
|
|
6
17
|
|
|
7
18
|
Use production by default. Use these flags only when a Toggl engineer asks for staging or a named MS environment.
|
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: toggl-cli
|
|
3
|
-
description: Use the Toggl CLI to work with Toggl
|
|
3
|
+
description: Use the Toggl CLI to work with Toggl 2.0 tasks, projects, time entries, time blocks, workspaces, authentication, and CLI maintenance from an agent-friendly terminal workflow. Trigger when the user asks to inspect or modify Toggl 2.0 data through the terminal, authenticate Toggl, switch workspaces, install or refresh the Toggl agent skill, update the CLI, or automate Toggl 2.0 workflows.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Toggl CLI
|
|
7
7
|
|
|
8
|
-
Use the `toggl` command when the user wants to inspect or modify Toggl
|
|
8
|
+
Use the `toggl` command when the user wants to inspect or modify Toggl 2.0 data from the terminal. The CLI is designed for agents: commands are non-interactive when flags are supplied, `--json` gives compact machine-readable responses, validation errors are explicit, and destructive operations require confirmation flags.
|
|
9
9
|
|
|
10
10
|
## When to Use
|
|
11
11
|
|
|
12
12
|
Use this skill when the task involves:
|
|
13
13
|
|
|
14
|
-
- Listing, reading, creating, updating, or deleting Toggl
|
|
14
|
+
- Listing, reading, creating, updating, or deleting Toggl 2.0 tasks, projects, time blocks, or time entries.
|
|
15
15
|
- Managing saved views, custom fields (admin), and task/project attachments (including file upload and download).
|
|
16
16
|
- Finding workspace metadata such as statuses, users, and workspace IDs.
|
|
17
17
|
- Authenticating the Toggl CLI, switching saved profiles, or switching the active workspace.
|
|
18
18
|
- Installing or refreshing the CLI's agent skill (`toggl skill setup`, or `toggl skill sync` after upgrading `@toggl/cli`).
|
|
19
19
|
- Updating a globally installed `@toggl/cli`.
|
|
20
|
-
- Automating a
|
|
20
|
+
- Automating a Toggl 2.0 workflow from shell commands.
|
|
21
21
|
|
|
22
|
-
Do not use this skill for Toggl Track APIs, raw
|
|
22
|
+
Do not use this skill for Toggl Track APIs, raw Toggl 2.0 API calls, or MCP server implementation work unless the user specifically asks to operate through the CLI.
|
|
23
23
|
|
|
24
24
|
## Operating Rules
|
|
25
25
|
|
|
@@ -43,14 +43,14 @@ Do not use this skill for Toggl Track APIs, raw Focus API calls, or MCP server i
|
|
|
43
43
|
|
|
44
44
|
## Read Next
|
|
45
45
|
|
|
46
|
-
-
|
|
46
|
+
- Toggl 2.0 concepts, entity hierarchy, and resource relationships: `reference/focus-concepts.md`
|
|
47
47
|
- Auth, profiles, and workspaces: `reference/auth-environments-workspaces.md`
|
|
48
48
|
- Command shape, JSON input, output, dates, and safety flags: `reference/command-contract.md`
|
|
49
49
|
- Tasks: `reference/tasks.md`
|
|
50
50
|
- Projects: `reference/projects.md`
|
|
51
51
|
- Time entries: `reference/time-entries.md`
|
|
52
52
|
- Time blocks: `reference/time-blocks.md`
|
|
53
|
-
- Rates and billables (
|
|
53
|
+
- Rates and billables (Toggl 2.0 API vs Track): `reference/rates-and-billables.md`
|
|
54
54
|
- Statuses and users: `reference/statuses-users.md`
|
|
55
55
|
- Reports (`get-workload` vs `get-flexq-data`): `reference/reports.md`
|
|
56
56
|
- Common multi-step flows: `workflows/common-workflows.md`
|
|
@@ -23,7 +23,7 @@ toggl auth --code 'https://accounts.toggl.com/focus/cli/auth-code?code=YOUR_CODE
|
|
|
23
23
|
|
|
24
24
|
The default `toggl auth` flow still uses `http://localhost:8716/callback` on the same machine and shows a branded success page in the browser tab.
|
|
25
25
|
|
|
26
|
-
The same flags work for `npx @
|
|
26
|
+
The same flags work for `npx @togglhq/mcp auth` when running the MCP package entrypoint outside the MCP host.
|
|
27
27
|
|
|
28
28
|
If the account has multiple workspaces, pass the workspace explicitly:
|
|
29
29
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Toggl 2.0 Concepts
|
|
2
2
|
|
|
3
|
-
Use this file to understand how Toggl
|
|
3
|
+
Use this file to understand how Toggl 2.0 entities relate to each other before choosing CLI commands.
|
|
4
4
|
|
|
5
5
|
## Mental Model
|
|
6
6
|
|
|
7
|
-
Toggl
|
|
7
|
+
Toggl 2.0 is organized around work that happens inside a workspace:
|
|
8
8
|
|
|
9
9
|
```text
|
|
10
10
|
Environment/Profile
|
|
@@ -27,7 +27,7 @@ A profile stores credentials and the selected workspace. Use profiles when the u
|
|
|
27
27
|
|
|
28
28
|
### Workspace
|
|
29
29
|
|
|
30
|
-
A workspace is the top-level
|
|
30
|
+
A workspace is the top-level context for projects, tasks, statuses, users, time entries, and time blocks. Most IDs only make sense inside the active workspace.
|
|
31
31
|
|
|
32
32
|
Use workspace commands when the agent needs to list available workspaces, refresh workspace metadata, switch the default workspace, or override the workspace for one command.
|
|
33
33
|
|
|
@@ -63,7 +63,7 @@ Use time entries when the user wants to track work, start a break, stop tracking
|
|
|
63
63
|
|
|
64
64
|
A time block represents scheduled or planned work. Time blocks usually belong to a task and have explicit start/end times.
|
|
65
65
|
|
|
66
|
-
Use time blocks when the user wants to schedule, plan, move, inspect, or delete calendar-like
|
|
66
|
+
Use time blocks when the user wants to schedule, plan, move, inspect, or delete calendar-like time blocks.
|
|
67
67
|
|
|
68
68
|
## Choosing the Right Command
|
|
69
69
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Projects
|
|
2
2
|
|
|
3
|
-
Use project commands to list
|
|
3
|
+
Use project commands to list projects, resolve project IDs, create projects, rename projects, and delete projects.
|
|
4
4
|
|
|
5
5
|
## Commands
|
|
6
6
|
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
There are **two different systems**. Pick the one that matches where the user is working.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Toggl 2.0 billable / labor rate schedules (this CLI)
|
|
6
6
|
|
|
7
|
-
Workspace and project **billable rate schedules** live under `toggl rates billable …` (nested under `rates`; same endpoints as the former top-level `billable-rates` command). **Labor cost rate** schedules use `toggl rates labor …` when your generated catalog includes them. Typical verbs: upserts, ranged deletes, conflict checks, and reads for workspace/project and per-user overlays (`get-*`, `upsert-*`, `delete-*-range`, `check-*-conflicts`). Use these when the task is **
|
|
7
|
+
Workspace and project **billable rate schedules** live under `toggl rates billable …` (nested under `rates`; same endpoints as the former top-level `billable-rates` command). **Labor cost rate** schedules use `toggl rates labor …` when your generated catalog includes them. Typical verbs: upserts, ranged deletes, conflict checks, and reads for workspace/project and per-user overlays (`get-*`, `upsert-*`, `delete-*-range`, `check-*-conflicts`). Use these when the task is **Toggl 2.0 billing configuration** or **Toggl 2.0 API rate data**.
|
|
8
8
|
|
|
9
9
|
## Track workspace assignment / Members UI
|
|
10
10
|
|
|
11
|
-
**Track** exposes member and workspace defaults such as **`track_billable_rate`** (and related assignment flows in the **Members** area of the Track product). That path is **not** the
|
|
11
|
+
**Track** exposes member and workspace defaults such as **`track_billable_rate`** (and related assignment flows in the **Members** area of the Track product). That path is **not** the Toggl 2.0 `rates billable` endpoints. If someone is changing rates **only in Track’s member/project assignment UI**, use Track’s APIs or the Track web app — do not assume the Toggl 2.0 CLI commands wrote the same field.
|
|
12
12
|
|
|
13
|
-
**Rule of thumb:**
|
|
13
|
+
**Rule of thumb:** Toggl 2.0 CLI `rates billable` (and `rates labor` when present) ↔ Toggl 2.0 billing schedules. Track member default rate ↔ Track/Members and Track APIs.
|