@bretwardjames/tw-bridge 0.7.1 → 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.
Files changed (2) hide show
  1. package/dist/cli.js +112 -3
  2. 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 getActiveMeetings() {
1094
+ function getActiveEntries(prefix) {
1095
1095
  const tracking = loadTracking();
1096
- return Object.entries(tracking).filter(([key]) => key.startsWith("meeting:")).map(([key, tags]) => ({ key, tags }));
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(" meeting Track meetings in Timewarrior (no task created)");
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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bretwardjames/tw-bridge",
3
- "version": "0.7.1",
3
+ "version": "0.8.0",
4
4
  "description": "Taskwarrior backend bridge — unified sync and hooks for multiple task management platforms",
5
5
  "type": "module",
6
6
  "license": "MIT",