@bretwardjames/tw-bridge 0.6.0 → 0.7.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 +101 -0
- package/dist/hooks/on-modify.js +1 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1006,6 +1006,34 @@ function completeTask(existing, keepTags) {
|
|
|
1006
1006
|
);
|
|
1007
1007
|
return result.status === 0;
|
|
1008
1008
|
}
|
|
1009
|
+
function findTaskByBackendId(backend, backendId) {
|
|
1010
|
+
const existing = getExistingTasks(backend);
|
|
1011
|
+
return existing.get(backendId) ?? null;
|
|
1012
|
+
}
|
|
1013
|
+
function startTask(uuid) {
|
|
1014
|
+
const result = spawnSync2(
|
|
1015
|
+
"task",
|
|
1016
|
+
["rc.confirmation=off", uuid, "start"],
|
|
1017
|
+
{
|
|
1018
|
+
encoding: "utf-8",
|
|
1019
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
1020
|
+
env: { ...process.env, TW_BRIDGE_REVERSE_SYNC: "1" }
|
|
1021
|
+
}
|
|
1022
|
+
);
|
|
1023
|
+
return result.status === 0;
|
|
1024
|
+
}
|
|
1025
|
+
function doneTask(uuid) {
|
|
1026
|
+
const result = spawnSync2(
|
|
1027
|
+
"task",
|
|
1028
|
+
["rc.confirmation=off", uuid, "done"],
|
|
1029
|
+
{
|
|
1030
|
+
encoding: "utf-8",
|
|
1031
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
1032
|
+
env: { ...process.env, TW_BRIDGE_REVERSE_SYNC: "1" }
|
|
1033
|
+
}
|
|
1034
|
+
);
|
|
1035
|
+
return result.status === 0;
|
|
1036
|
+
}
|
|
1009
1037
|
function updateTaskDescription(existing, newDescription) {
|
|
1010
1038
|
if (existing.description === newDescription) return false;
|
|
1011
1039
|
const result = spawnSync2(
|
|
@@ -1074,6 +1102,8 @@ var commands = {
|
|
|
1074
1102
|
add: addBackend,
|
|
1075
1103
|
install,
|
|
1076
1104
|
sync,
|
|
1105
|
+
start: startCmd,
|
|
1106
|
+
done: doneCmd,
|
|
1077
1107
|
meeting: meetingCmd,
|
|
1078
1108
|
timewarrior: timewarriorCmd,
|
|
1079
1109
|
which,
|
|
@@ -1087,6 +1117,8 @@ async function main() {
|
|
|
1087
1117
|
console.log(" add Add a new backend instance");
|
|
1088
1118
|
console.log(" install Install Taskwarrior hooks and shell integration");
|
|
1089
1119
|
console.log(" sync Pull tasks from all backends");
|
|
1120
|
+
console.log(" start Start a task by backend ID (e.g., tw-bridge start ghp#123)");
|
|
1121
|
+
console.log(" done Complete a task by backend ID (e.g., tw-bridge done ghp#123)");
|
|
1090
1122
|
console.log(" meeting Track meetings in Timewarrior (no task created)");
|
|
1091
1123
|
console.log(" timewarrior Manage Timewarrior integration");
|
|
1092
1124
|
console.log(" which Print the context for the current directory");
|
|
@@ -1502,6 +1534,75 @@ async function sync() {
|
|
|
1502
1534
|
await syncBackend(name, config.backends[name], config);
|
|
1503
1535
|
}
|
|
1504
1536
|
}
|
|
1537
|
+
function parseBackendRef(ref) {
|
|
1538
|
+
const match = ref.match(/^([^#]+)#(.+)$/);
|
|
1539
|
+
if (!match) return null;
|
|
1540
|
+
return { backend: match[1], id: match[2] };
|
|
1541
|
+
}
|
|
1542
|
+
async function resolveTaskByRef(ref) {
|
|
1543
|
+
const config = loadConfig();
|
|
1544
|
+
const backendName = Object.keys(config.backends).find(
|
|
1545
|
+
(name) => name === ref.backend || config.backends[name].adapter === ref.backend
|
|
1546
|
+
);
|
|
1547
|
+
if (!backendName) {
|
|
1548
|
+
console.error(`No backend found matching "${ref.backend}".`);
|
|
1549
|
+
console.error(`Configured backends: ${Object.keys(config.backends).join(", ")}`);
|
|
1550
|
+
process.exit(1);
|
|
1551
|
+
}
|
|
1552
|
+
let task = findTaskByBackendId(backendName, ref.id);
|
|
1553
|
+
if (!task) {
|
|
1554
|
+
console.log(`Task #${ref.id} not in Taskwarrior yet, syncing ${backendName}...`);
|
|
1555
|
+
await syncBackend(backendName, config.backends[backendName], config);
|
|
1556
|
+
task = findTaskByBackendId(backendName, ref.id);
|
|
1557
|
+
}
|
|
1558
|
+
if (!task) {
|
|
1559
|
+
console.error(`Task #${ref.id} not found in backend "${backendName}" after sync.`);
|
|
1560
|
+
process.exit(1);
|
|
1561
|
+
}
|
|
1562
|
+
return task;
|
|
1563
|
+
}
|
|
1564
|
+
async function startCmd() {
|
|
1565
|
+
const ref = process.argv[3];
|
|
1566
|
+
if (!ref || ref.startsWith("--")) {
|
|
1567
|
+
console.error("Usage: tw-bridge start <backend>#<id> (e.g., tw-bridge start ghp#123)");
|
|
1568
|
+
process.exit(1);
|
|
1569
|
+
}
|
|
1570
|
+
const parsed = parseBackendRef(ref);
|
|
1571
|
+
if (!parsed) {
|
|
1572
|
+
console.error(`Invalid reference "${ref}". Expected format: backend#id (e.g., ghp#123)`);
|
|
1573
|
+
process.exit(1);
|
|
1574
|
+
}
|
|
1575
|
+
const task = await resolveTaskByRef(parsed);
|
|
1576
|
+
if (task.start) {
|
|
1577
|
+
console.log(`Task #${parsed.id} is already started (${task.uuid.slice(0, 8)})`);
|
|
1578
|
+
return;
|
|
1579
|
+
}
|
|
1580
|
+
if (startTask(task.uuid)) {
|
|
1581
|
+
console.log(`Started: [#${parsed.id}] ${task.description} (${task.uuid.slice(0, 8)})`);
|
|
1582
|
+
} else {
|
|
1583
|
+
console.error(`Failed to start task ${task.uuid}`);
|
|
1584
|
+
process.exit(1);
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1587
|
+
async function doneCmd() {
|
|
1588
|
+
const ref = process.argv[3];
|
|
1589
|
+
if (!ref || ref.startsWith("--")) {
|
|
1590
|
+
console.error("Usage: tw-bridge done <backend>#<id> (e.g., tw-bridge done ghp#123)");
|
|
1591
|
+
process.exit(1);
|
|
1592
|
+
}
|
|
1593
|
+
const parsed = parseBackendRef(ref);
|
|
1594
|
+
if (!parsed) {
|
|
1595
|
+
console.error(`Invalid reference "${ref}". Expected format: backend#id (e.g., ghp#123)`);
|
|
1596
|
+
process.exit(1);
|
|
1597
|
+
}
|
|
1598
|
+
const task = await resolveTaskByRef(parsed);
|
|
1599
|
+
if (doneTask(task.uuid)) {
|
|
1600
|
+
console.log(`Completed: [#${parsed.id}] ${task.description} (${task.uuid.slice(0, 8)})`);
|
|
1601
|
+
} else {
|
|
1602
|
+
console.error(`Failed to complete task ${task.uuid}`);
|
|
1603
|
+
process.exit(1);
|
|
1604
|
+
}
|
|
1605
|
+
}
|
|
1505
1606
|
async function syncBackend(name, backend, config) {
|
|
1506
1607
|
const adapter = await resolveAdapter(
|
|
1507
1608
|
{ backend: name },
|
package/dist/hooks/on-modify.js
CHANGED
|
@@ -1068,6 +1068,7 @@ async function main() {
|
|
|
1068
1068
|
} else if (wasStopped || wasCompleted) {
|
|
1069
1069
|
handleTimewarriorStop(config, oldTask);
|
|
1070
1070
|
}
|
|
1071
|
+
if (process.env.TW_BRIDGE_REVERSE_SYNC) return;
|
|
1071
1072
|
const adapter = await resolveAdapter(newTask, config);
|
|
1072
1073
|
if (!adapter) return;
|
|
1073
1074
|
if (wasStarted && adapter.onStart) {
|