@bretwardjames/tw-bridge 0.7.0 → 0.8.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/dist/cli.js +130 -7
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1091,9 +1091,12 @@ function stopEntry(key) {
|
|
|
1091
1091
|
spawnSync3("timew", ["start", ...remaining], { stdio: "pipe" });
|
|
1092
1092
|
}
|
|
1093
1093
|
}
|
|
1094
|
-
function
|
|
1094
|
+
function getActiveEntries(prefix) {
|
|
1095
1095
|
const tracking = loadTracking();
|
|
1096
|
-
return Object.entries(tracking).filter(([key]) => key.startsWith(
|
|
1096
|
+
return Object.entries(tracking).filter(([key]) => key.startsWith(prefix)).map(([key, tags]) => ({ key, tags }));
|
|
1097
|
+
}
|
|
1098
|
+
function getActiveMeetings() {
|
|
1099
|
+
return getActiveEntries("meeting:");
|
|
1097
1100
|
}
|
|
1098
1101
|
|
|
1099
1102
|
// src/cli.ts
|
|
@@ -1104,6 +1107,7 @@ var commands = {
|
|
|
1104
1107
|
sync,
|
|
1105
1108
|
start: startCmd,
|
|
1106
1109
|
done: doneCmd,
|
|
1110
|
+
track: trackCmd,
|
|
1107
1111
|
meeting: meetingCmd,
|
|
1108
1112
|
timewarrior: timewarriorCmd,
|
|
1109
1113
|
which,
|
|
@@ -1119,7 +1123,8 @@ async function main() {
|
|
|
1119
1123
|
console.log(" sync Pull tasks from all backends");
|
|
1120
1124
|
console.log(" start Start a task by backend ID (e.g., tw-bridge start ghp#123)");
|
|
1121
1125
|
console.log(" done Complete a task by backend ID (e.g., tw-bridge done ghp#123)");
|
|
1122
|
-
console.log("
|
|
1126
|
+
console.log(" track Track non-task time (e.g., tw-bridge track emails --project ghp)");
|
|
1127
|
+
console.log(" meeting Track meetings (alias for: track start <name> --type meeting)");
|
|
1123
1128
|
console.log(" timewarrior Manage Timewarrior integration");
|
|
1124
1129
|
console.log(" which Print the context for the current directory");
|
|
1125
1130
|
console.log(" config Show current configuration");
|
|
@@ -1247,6 +1252,110 @@ function installTimewExtension() {
|
|
|
1247
1252
|
Installed Timewarrior extension: ${extTarget} -> ${extSource}`);
|
|
1248
1253
|
console.log(" Usage: timew bridge [task-time|wall-time] [project-filter]");
|
|
1249
1254
|
}
|
|
1255
|
+
function sanitizeName(name) {
|
|
1256
|
+
return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
1257
|
+
}
|
|
1258
|
+
async function trackCmd() {
|
|
1259
|
+
const sub = process.argv[3];
|
|
1260
|
+
if (!sub || sub === "--help") {
|
|
1261
|
+
console.log("Usage: tw-bridge track <subcommand>\n");
|
|
1262
|
+
console.log("Subcommands:");
|
|
1263
|
+
console.log(" start <activity> [--project <tag>] [--switch] Start tracking an activity");
|
|
1264
|
+
console.log(" stop [activity] Stop an activity (or all if no name)");
|
|
1265
|
+
console.log(" list Show active non-task tracking");
|
|
1266
|
+
console.log("\nActivities are tracked in Timewarrior only \u2014 no Taskwarrior task is created.");
|
|
1267
|
+
console.log("By default, activities run in parallel with active tasks.");
|
|
1268
|
+
console.log("Use --switch to pause active tasks instead.");
|
|
1269
|
+
console.log("\nExamples:");
|
|
1270
|
+
console.log(" tw-bridge track start emails --project ghp");
|
|
1271
|
+
console.log(" tw-bridge track start comms");
|
|
1272
|
+
console.log(" tw-bridge track stop emails");
|
|
1273
|
+
return;
|
|
1274
|
+
}
|
|
1275
|
+
const config = loadConfig();
|
|
1276
|
+
if (!config.timewarrior?.enabled) {
|
|
1277
|
+
console.error("Timewarrior is not enabled. Run: tw-bridge timewarrior enable");
|
|
1278
|
+
process.exit(1);
|
|
1279
|
+
}
|
|
1280
|
+
if (sub === "start") {
|
|
1281
|
+
const switchMode = process.argv.includes("--switch") || process.argv.includes("-s");
|
|
1282
|
+
const projectFlag = parseFlag("--project");
|
|
1283
|
+
const nameArgs = [];
|
|
1284
|
+
const args = process.argv.slice(4);
|
|
1285
|
+
for (let i = 0; i < args.length; i++) {
|
|
1286
|
+
if (args[i] === "--project") {
|
|
1287
|
+
i++;
|
|
1288
|
+
continue;
|
|
1289
|
+
}
|
|
1290
|
+
if (args[i].startsWith("--") || args[i] === "-s") continue;
|
|
1291
|
+
nameArgs.push(args[i]);
|
|
1292
|
+
}
|
|
1293
|
+
const nameArg = nameArgs.join(" ");
|
|
1294
|
+
if (!nameArg) {
|
|
1295
|
+
console.error("Usage: tw-bridge track start <activity>");
|
|
1296
|
+
process.exit(1);
|
|
1297
|
+
}
|
|
1298
|
+
const tag = sanitizeName(nameArg);
|
|
1299
|
+
const key = `track:${tag}`;
|
|
1300
|
+
const tags = [tag];
|
|
1301
|
+
const project = projectFlag ?? detectProjectContext();
|
|
1302
|
+
if (project) tags.push(project);
|
|
1303
|
+
if (switchMode) {
|
|
1304
|
+
startSwitch(key, tags);
|
|
1305
|
+
} else {
|
|
1306
|
+
startParallel(key, tags);
|
|
1307
|
+
}
|
|
1308
|
+
console.log(`Tracking: ${nameArg}`);
|
|
1309
|
+
console.log(` Tags: ${tags.join(" ")}`);
|
|
1310
|
+
if (!switchMode) {
|
|
1311
|
+
console.log(" Mode: parallel (active tasks continue tracking)");
|
|
1312
|
+
} else {
|
|
1313
|
+
console.log(" Mode: switch (active tasks paused)");
|
|
1314
|
+
}
|
|
1315
|
+
return;
|
|
1316
|
+
}
|
|
1317
|
+
if (sub === "stop") {
|
|
1318
|
+
const nameArg = process.argv.slice(4).join(" ").trim();
|
|
1319
|
+
const active = getActiveEntries("track:");
|
|
1320
|
+
if (active.length === 0) {
|
|
1321
|
+
console.log("No active tracking.");
|
|
1322
|
+
return;
|
|
1323
|
+
}
|
|
1324
|
+
if (nameArg) {
|
|
1325
|
+
const tag = sanitizeName(nameArg);
|
|
1326
|
+
const key = `track:${tag}`;
|
|
1327
|
+
const match = active.find((m) => m.key === key);
|
|
1328
|
+
if (!match) {
|
|
1329
|
+
console.error(`No active tracking matching "${nameArg}".`);
|
|
1330
|
+
console.error(`Active: ${active.map((m) => m.key.replace("track:", "")).join(", ")}`);
|
|
1331
|
+
process.exit(1);
|
|
1332
|
+
}
|
|
1333
|
+
stopEntry(key);
|
|
1334
|
+
console.log(`Stopped tracking: ${nameArg}`);
|
|
1335
|
+
} else {
|
|
1336
|
+
for (const m of active) {
|
|
1337
|
+
stopEntry(m.key);
|
|
1338
|
+
}
|
|
1339
|
+
console.log(`Stopped ${active.length} activity(s): ${active.map((m) => m.key.replace("track:", "")).join(", ")}`);
|
|
1340
|
+
}
|
|
1341
|
+
return;
|
|
1342
|
+
}
|
|
1343
|
+
if (sub === "list") {
|
|
1344
|
+
const active = getActiveEntries("track:");
|
|
1345
|
+
if (active.length === 0) {
|
|
1346
|
+
console.log("No active tracking.");
|
|
1347
|
+
return;
|
|
1348
|
+
}
|
|
1349
|
+
console.log("Active tracking:");
|
|
1350
|
+
for (const m of active) {
|
|
1351
|
+
const name = m.key.replace("track:", "");
|
|
1352
|
+
console.log(` ${name} (${m.tags.join(" ")})`);
|
|
1353
|
+
}
|
|
1354
|
+
return;
|
|
1355
|
+
}
|
|
1356
|
+
console.error(`Unknown subcommand: ${sub}`);
|
|
1357
|
+
process.exit(1);
|
|
1358
|
+
}
|
|
1250
1359
|
function sanitizeMeetingName(name) {
|
|
1251
1360
|
return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
1252
1361
|
}
|
|
@@ -1541,11 +1650,25 @@ function parseBackendRef(ref) {
|
|
|
1541
1650
|
}
|
|
1542
1651
|
async function resolveTaskByRef(ref) {
|
|
1543
1652
|
const config = loadConfig();
|
|
1544
|
-
const
|
|
1545
|
-
|
|
1546
|
-
)
|
|
1653
|
+
const repo = parseFlag("--repo");
|
|
1654
|
+
let backendName;
|
|
1655
|
+
if (repo) {
|
|
1656
|
+
const repoName = repo.includes("/") ? repo.split("/").pop() : repo;
|
|
1657
|
+
backendName = Object.keys(config.backends).find((name) => {
|
|
1658
|
+
const b = config.backends[name];
|
|
1659
|
+
if (b.adapter !== ref.backend && name !== ref.backend) return false;
|
|
1660
|
+
const project = b.config?.project;
|
|
1661
|
+
const cwdBase = b.config?.cwd ? path6.basename(b.config.cwd) : void 0;
|
|
1662
|
+
return project?.toLowerCase() === repoName.toLowerCase() || cwdBase?.toLowerCase() === repoName.toLowerCase();
|
|
1663
|
+
});
|
|
1664
|
+
}
|
|
1665
|
+
if (!backendName) {
|
|
1666
|
+
backendName = Object.keys(config.backends).find(
|
|
1667
|
+
(name) => name === ref.backend || config.backends[name].adapter === ref.backend
|
|
1668
|
+
);
|
|
1669
|
+
}
|
|
1547
1670
|
if (!backendName) {
|
|
1548
|
-
console.error(`No backend found matching "${ref.backend}".`);
|
|
1671
|
+
console.error(`No backend found matching "${ref.backend}"${repo ? ` for repo "${repo}"` : ""}.`);
|
|
1549
1672
|
console.error(`Configured backends: ${Object.keys(config.backends).join(", ")}`);
|
|
1550
1673
|
process.exit(1);
|
|
1551
1674
|
}
|