@tekmidian/pai 0.13.0 → 0.13.2
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/index.mjs +1 -1
- package/dist/cli/program.mjs +1 -1
- package/dist/config-C8m-tPhP.mjs.map +1 -1
- package/dist/daemon-mcp/index.mjs +1 -1
- package/dist/daemon-mcp/index.mjs.map +1 -1
- package/dist/{pick-CS_TmOqX.mjs → pick-C5ziUh1b.mjs} +126 -11
- package/dist/pick-C5ziUh1b.mjs.map +1 -0
- package/dist/skills/Tasks/SKILL.md +1 -1
- package/docs/commands/README.md +1 -0
- package/docs/commands/task.md +18 -0
- package/package.json +1 -1
- package/dist/pick-CS_TmOqX.mjs.map +0 -1
|
@@ -6535,8 +6535,23 @@ async function dispatchAll(tasks, opts) {
|
|
|
6535
6535
|
*
|
|
6536
6536
|
* See Notes/docs/task-bus.md.
|
|
6537
6537
|
*/
|
|
6538
|
-
/**
|
|
6539
|
-
|
|
6538
|
+
/**
|
|
6539
|
+
* How long AIBroker may spend on one dispatch, in seconds.
|
|
6540
|
+
*
|
|
6541
|
+
* A cold spawn measured ~10s on an idle machine, but boot time is not bounded:
|
|
6542
|
+
* under load a session can take considerably longer to start accepting input.
|
|
6543
|
+
*/
|
|
6544
|
+
const DEFAULT_DISPATCH_TIMEOUT_SECS = 180;
|
|
6545
|
+
/**
|
|
6546
|
+
* Margin between AIBroker's own deadline and when we kill the process.
|
|
6547
|
+
*
|
|
6548
|
+
* These two timeouts must never disagree. If ours fired first we would kill a
|
|
6549
|
+
* dispatch mid-flight and report a transport failure that AIBroker cannot
|
|
6550
|
+
* reproduce from its own CLI — a phantom bug, in the other repo, with no trace
|
|
6551
|
+
* on either side. So we always pass our budget down via `--timeout` and give
|
|
6552
|
+
* it room to time out first and tell us why.
|
|
6553
|
+
*/
|
|
6554
|
+
const KILL_MARGIN_MS = 15e3;
|
|
6540
6555
|
const VALID_OUTCOMES = new Set([
|
|
6541
6556
|
"delivered",
|
|
6542
6557
|
"spawned",
|
|
@@ -6551,10 +6566,10 @@ const VALID_OUTCOMES = new Set([
|
|
|
6551
6566
|
* and reasoning, so they are long, multi-line, and full of quotes and
|
|
6552
6567
|
* backticks. argv would mangle them or hit length limits.
|
|
6553
6568
|
*/
|
|
6554
|
-
function run(bin, args, stdin) {
|
|
6569
|
+
function run(bin, args, stdin, killAfterMs) {
|
|
6555
6570
|
return new Promise((resolve, reject) => {
|
|
6556
6571
|
execFile(bin, args, {
|
|
6557
|
-
timeout:
|
|
6572
|
+
timeout: killAfterMs,
|
|
6558
6573
|
maxBuffer: 1024 * 1024
|
|
6559
6574
|
}, (error, stdout, stderr) => {
|
|
6560
6575
|
if (error && !stdout.trim().startsWith("{")) {
|
|
@@ -6566,18 +6581,21 @@ function run(bin, args, stdin) {
|
|
|
6566
6581
|
});
|
|
6567
6582
|
}
|
|
6568
6583
|
var AiBrokerTransport = class {
|
|
6569
|
-
constructor(bin = "aibroker") {
|
|
6584
|
+
constructor(bin = "aibroker", timeoutSecs = DEFAULT_DISPATCH_TIMEOUT_SECS) {
|
|
6570
6585
|
this.bin = bin;
|
|
6586
|
+
this.timeoutSecs = timeoutSecs;
|
|
6571
6587
|
}
|
|
6572
6588
|
async dispatch(project, message, opts) {
|
|
6573
6589
|
const args = [
|
|
6574
6590
|
"dispatch",
|
|
6575
6591
|
project,
|
|
6576
6592
|
"--stdin",
|
|
6577
|
-
"--json"
|
|
6593
|
+
"--json",
|
|
6594
|
+
"--timeout",
|
|
6595
|
+
String(this.timeoutSecs)
|
|
6578
6596
|
];
|
|
6579
6597
|
if (!opts.spawnIfAbsent) args.push("--no-spawn");
|
|
6580
|
-
const stdout = await run(this.bin, args, message);
|
|
6598
|
+
const stdout = await run(this.bin, args, message, this.timeoutSecs * 1e3 + KILL_MARGIN_MS);
|
|
6581
6599
|
const start = stdout.lastIndexOf("{");
|
|
6582
6600
|
if (start === -1) throw new Error(`aibroker returned no JSON: ${stdout.trim().slice(0, 200)}`);
|
|
6583
6601
|
let wire;
|
|
@@ -6605,14 +6623,14 @@ var AiBrokerTransport = class {
|
|
|
6605
6623
|
* shipped for a long time without `dispatch`, and an older install would
|
|
6606
6624
|
* otherwise fail once per task instead of degrading cleanly up front.
|
|
6607
6625
|
*/
|
|
6608
|
-
async function detectAiBroker(bin = "aibroker") {
|
|
6626
|
+
async function detectAiBroker(bin = "aibroker", timeoutSecs = DEFAULT_DISPATCH_TIMEOUT_SECS) {
|
|
6609
6627
|
try {
|
|
6610
6628
|
return (await new Promise((resolve, reject) => {
|
|
6611
6629
|
execFile(bin, ["help"], { timeout: 1e4 }, (error, stdout, stderr) => {
|
|
6612
6630
|
if (error && !stdout) reject(error);
|
|
6613
6631
|
else resolve(stdout + stderr);
|
|
6614
6632
|
});
|
|
6615
|
-
})).includes("dispatch") ? new AiBrokerTransport(bin) : null;
|
|
6633
|
+
})).includes("dispatch") ? new AiBrokerTransport(bin, timeoutSecs) : null;
|
|
6616
6634
|
} catch {
|
|
6617
6635
|
return null;
|
|
6618
6636
|
}
|
|
@@ -6637,6 +6655,39 @@ function reportUnconfigured() {
|
|
|
6637
6655
|
function todayIso() {
|
|
6638
6656
|
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
6639
6657
|
}
|
|
6658
|
+
/**
|
|
6659
|
+
* Prompt for a secret without echoing it.
|
|
6660
|
+
*
|
|
6661
|
+
* Never accept a token as a command-line argument: argv is visible in `ps` to
|
|
6662
|
+
* every user on the machine and lands in shell history verbatim.
|
|
6663
|
+
*/
|
|
6664
|
+
function promptSecret(question) {
|
|
6665
|
+
return new Promise((resolve) => {
|
|
6666
|
+
const rl = createInterface({
|
|
6667
|
+
input: process.stdin,
|
|
6668
|
+
output: process.stdout,
|
|
6669
|
+
terminal: true
|
|
6670
|
+
});
|
|
6671
|
+
const out = process.stdout;
|
|
6672
|
+
const write = out.write.bind(out);
|
|
6673
|
+
rl._writeToOutput = (s) => {
|
|
6674
|
+
if (!out.muted) write(s);
|
|
6675
|
+
};
|
|
6676
|
+
write(question);
|
|
6677
|
+
out.muted = true;
|
|
6678
|
+
rl.question("", (answer) => {
|
|
6679
|
+
out.muted = false;
|
|
6680
|
+
write("\n");
|
|
6681
|
+
rl.close();
|
|
6682
|
+
resolve(answer.trim());
|
|
6683
|
+
});
|
|
6684
|
+
});
|
|
6685
|
+
}
|
|
6686
|
+
/** Show enough of a token to recognise it, never enough to use it. */
|
|
6687
|
+
function redact(token) {
|
|
6688
|
+
if (!token) return dim("(not set)");
|
|
6689
|
+
return token.length <= 8 ? "********" : `${token.slice(0, 4)}…${token.slice(-4)}`;
|
|
6690
|
+
}
|
|
6640
6691
|
function renderOwner(task) {
|
|
6641
6692
|
if (task.owner.project) {
|
|
6642
6693
|
const via = task.owner.source === "label" ? "label" : "container";
|
|
@@ -6723,7 +6774,7 @@ function registerTaskCommands(taskCmd) {
|
|
|
6723
6774
|
console.log(dim(" Nothing to dispatch."));
|
|
6724
6775
|
return;
|
|
6725
6776
|
}
|
|
6726
|
-
const transport = opts.dryRun ? null : await detectAiBroker();
|
|
6777
|
+
const transport = opts.dryRun ? null : await detectAiBroker(void 0, config.tasks?.dispatchTimeoutSecs);
|
|
6727
6778
|
if (!opts.dryRun && !transport) console.log(dim(" No aibroker CLI with `dispatch` found — reporting ownership only."));
|
|
6728
6779
|
printResults(await dispatchAll(tasks, {
|
|
6729
6780
|
transport,
|
|
@@ -6731,6 +6782,70 @@ function registerTaskCommands(taskCmd) {
|
|
|
6731
6782
|
spawnIfAbsent: opts.spawn !== false
|
|
6732
6783
|
}));
|
|
6733
6784
|
});
|
|
6785
|
+
taskCmd.command("config").description("View or change task bus settings without running the full setup wizard").option("--token", "Prompt for the Todoist API token (input is hidden)").option("--from-env", "Adopt the token from TODOIST_API_KEY in the environment").option("--project <id>", "Tracker project ID that roots the bus (an ID, never a name)").option("--findings <id>", "Section ID for the findings inbox").option("--timeout <secs>", "Seconds a single dispatch may take", (v) => Number.parseInt(v, 10)).option("--auto-dispatch <bool>", "Hand tasks to owning sessions automatically (true/false)").option("--disable", "Turn the task bus off without discarding its settings").action(async (opts) => {
|
|
6786
|
+
const raw = readConfigRaw();
|
|
6787
|
+
const tasks = raw.tasks ?? {};
|
|
6788
|
+
tasks.providers ??= {};
|
|
6789
|
+
tasks.providers.todoist ??= {};
|
|
6790
|
+
const todoist = tasks.providers.todoist;
|
|
6791
|
+
if (!opts.token && !opts.fromEnv && !opts.project && !opts.findings && opts.timeout === void 0 && opts.autoDispatch === void 0 && !opts.disable) {
|
|
6792
|
+
console.log();
|
|
6793
|
+
console.log(` ${bold("Task bus")} ${tasks.enabled ? chalk.green("enabled") : dim("disabled")}`);
|
|
6794
|
+
console.log(` ${bold("Token")} ${redact(todoist.apiKey)}${!todoist.apiKey && process.env.TODOIST_API_KEY ? dim(" (TODOIST_API_KEY is set in this shell)") : ""}`);
|
|
6795
|
+
console.log(` ${bold("Root project")} ${todoist.rootProjectId ?? dim("(not set)")}`);
|
|
6796
|
+
console.log(` ${bold("Findings")} ${todoist.findingsSectionId ?? dim("(not set)")}`);
|
|
6797
|
+
console.log(` ${bold("Auto-dispatch")} ${tasks.autoDispatch ? chalk.green("on") : dim("off")}`);
|
|
6798
|
+
console.log(` ${bold("Timeout")} ${tasks.dispatchTimeoutSecs ?? dim("default (180s)")}`);
|
|
6799
|
+
console.log();
|
|
6800
|
+
console.log(dim(` ${CONFIG_FILE$2}`));
|
|
6801
|
+
console.log();
|
|
6802
|
+
return;
|
|
6803
|
+
}
|
|
6804
|
+
if (opts.token && opts.fromEnv) {
|
|
6805
|
+
console.error(chalk.yellow(" Use either --token or --from-env, not both."));
|
|
6806
|
+
process.exitCode = 1;
|
|
6807
|
+
return;
|
|
6808
|
+
}
|
|
6809
|
+
if (opts.fromEnv) {
|
|
6810
|
+
const envToken = process.env.TODOIST_API_KEY?.trim();
|
|
6811
|
+
if (!envToken) {
|
|
6812
|
+
console.error(chalk.yellow(" TODOIST_API_KEY is not set in this environment."));
|
|
6813
|
+
process.exitCode = 1;
|
|
6814
|
+
return;
|
|
6815
|
+
}
|
|
6816
|
+
todoist.apiKey = envToken;
|
|
6817
|
+
todoist.enabled = true;
|
|
6818
|
+
tasks.enabled = true;
|
|
6819
|
+
}
|
|
6820
|
+
if (opts.token) {
|
|
6821
|
+
const entered = await promptSecret(" Todoist API token (hidden): ");
|
|
6822
|
+
if (!entered) {
|
|
6823
|
+
console.error(chalk.yellow(" No token entered. Nothing changed."));
|
|
6824
|
+
process.exitCode = 1;
|
|
6825
|
+
return;
|
|
6826
|
+
}
|
|
6827
|
+
todoist.apiKey = entered;
|
|
6828
|
+
todoist.enabled = true;
|
|
6829
|
+
tasks.enabled = true;
|
|
6830
|
+
}
|
|
6831
|
+
if (opts.project) {
|
|
6832
|
+
todoist.rootProjectId = opts.project;
|
|
6833
|
+
tasks.enabled = true;
|
|
6834
|
+
}
|
|
6835
|
+
if (opts.findings) todoist.findingsSectionId = opts.findings;
|
|
6836
|
+
if (opts.timeout !== void 0) tasks.dispatchTimeoutSecs = opts.timeout;
|
|
6837
|
+
if (opts.autoDispatch !== void 0) tasks.autoDispatch = opts.autoDispatch === "true";
|
|
6838
|
+
if (opts.disable) tasks.enabled = false;
|
|
6839
|
+
raw.tasks = tasks;
|
|
6840
|
+
writeConfigRaw(raw);
|
|
6841
|
+
try {
|
|
6842
|
+
chmodSync(CONFIG_FILE$2, 384);
|
|
6843
|
+
} catch {
|
|
6844
|
+
console.log(chalk.yellow(` Could not restrict permissions on ${CONFIG_FILE$2} — check them by hand.`));
|
|
6845
|
+
}
|
|
6846
|
+
console.log(chalk.green(" Saved."));
|
|
6847
|
+
if (todoist.apiKey && !todoist.rootProjectId) console.log(dim(" No root project set yet — run `pai task config --project <id>`."));
|
|
6848
|
+
});
|
|
6734
6849
|
taskCmd.command("done <id>").description("Mark a task complete on the tracker").action(async (id) => {
|
|
6735
6850
|
const provider = buildProvider();
|
|
6736
6851
|
if (!provider) return reportUnconfigured();
|
|
@@ -8900,4 +9015,4 @@ async function cmdPick(db, opts = {}) {
|
|
|
8900
9015
|
|
|
8901
9016
|
//#endregion
|
|
8902
9017
|
export { registerDaemonCommands as C, registerProjectsCommands as D, registerRegistryCommands as E, findMovedPath as O, registerBackupCommands as S, registerMemoryCommands as T, registerObservationCommands as _, cmdPauseAll as a, registerSetupCommand as b, cmdPause as c, registerKgCommands as d, registerTopicCommands as f, registerSkillCommands as g, registerUpdateCommand as h, cmdClearNames as i, resolveIdentifier as k, registerHelpCommand as l, registerNotifyCommands as m, cmdFind as n, cmdGoto as o, registerTaskCommands as p, cmdList as r, cmdEnd as s, cmdPick as t, registerDbCommands as u, registerZettelCommands as v, registerMcpCommands as w, registerRestoreCommands as x, registerObsidianCommands as y };
|
|
8903
|
-
//# sourceMappingURL=pick-
|
|
9018
|
+
//# sourceMappingURL=pick-C5ziUh1b.mjs.map
|