@task0/cli 0.8.0 → 0.9.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/README.md +14 -6
- package/dist/main.js +62 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -65,15 +65,19 @@ task0 run <id> # drive the full triage → plan → refine → exec lo
|
|
|
65
65
|
## Run as a service (autostart on login / boot)
|
|
66
66
|
|
|
67
67
|
`task0 daemon register` installs an OS-level autostart service in addition to
|
|
68
|
-
recording the daemon identity.
|
|
69
|
-
|
|
68
|
+
recording the daemon identity. The server URL comes from the active profile's
|
|
69
|
+
`api_url` — set it once per profile, then `register` reads it. After registering
|
|
70
|
+
you can sign out, reboot, and the daemon reconnects on its own.
|
|
70
71
|
|
|
71
72
|
```sh
|
|
72
|
-
#
|
|
73
|
-
task0
|
|
73
|
+
# 1. Tell the active profile which server to talk to (once per profile)
|
|
74
|
+
task0 profile set api_url https://central.example.com:4318
|
|
74
75
|
|
|
75
|
-
#
|
|
76
|
-
|
|
76
|
+
# 2a. user-level (default) — starts at user login, no sudo needed
|
|
77
|
+
task0 daemon register
|
|
78
|
+
|
|
79
|
+
# 2b. system-level — starts at boot, runs without an active login
|
|
80
|
+
sudo -E task0 daemon register --system
|
|
77
81
|
|
|
78
82
|
# pause / resume without forgetting the identity
|
|
79
83
|
task0 daemon stop
|
|
@@ -83,6 +87,10 @@ task0 daemon start
|
|
|
83
87
|
task0 daemon logout
|
|
84
88
|
```
|
|
85
89
|
|
|
90
|
+
To target a different server for one invocation without writing it to the
|
|
91
|
+
profile, export `TASK0_API_URL` — it overrides the profile's `api_url` for
|
|
92
|
+
that shell session.
|
|
93
|
+
|
|
86
94
|
Per platform:
|
|
87
95
|
|
|
88
96
|
| Platform | Scope | File written |
|
package/dist/main.js
CHANGED
|
@@ -1306,6 +1306,9 @@ function profileExists(name) {
|
|
|
1306
1306
|
}
|
|
1307
1307
|
}
|
|
1308
1308
|
var activeProfileCache = null;
|
|
1309
|
+
function getActiveProfile() {
|
|
1310
|
+
return activeProfileCache;
|
|
1311
|
+
}
|
|
1309
1312
|
function activateProfile(argv) {
|
|
1310
1313
|
ensureDefaultProfile();
|
|
1311
1314
|
const flagValue = parseProfileFlag(argv);
|
|
@@ -1329,9 +1332,14 @@ function activateProfile(argv) {
|
|
|
1329
1332
|
}
|
|
1330
1333
|
}
|
|
1331
1334
|
process.env.TASK0_PROFILE = name;
|
|
1335
|
+
const envApiUrlOverride = process.env.TASK0_API_URL?.trim() || void 0;
|
|
1332
1336
|
const apiUrl = getApiUrl();
|
|
1333
|
-
activeProfileCache = {
|
|
1334
|
-
|
|
1337
|
+
activeProfileCache = {
|
|
1338
|
+
name,
|
|
1339
|
+
...apiUrl ? { apiUrl } : {},
|
|
1340
|
+
...envApiUrlOverride ? { envApiUrlOverride } : {}
|
|
1341
|
+
};
|
|
1342
|
+
if (apiUrl && !envApiUrlOverride) {
|
|
1335
1343
|
process.env.TASK0_API_URL = apiUrl;
|
|
1336
1344
|
}
|
|
1337
1345
|
}
|
|
@@ -1695,7 +1703,7 @@ function requireLocalDaemon() {
|
|
|
1695
1703
|
const id = localDaemonId();
|
|
1696
1704
|
if (!id) {
|
|
1697
1705
|
console.error(chalk.red("This host is not registered as a daemon."));
|
|
1698
|
-
console.error(chalk.dim("Run `task0 daemon register
|
|
1706
|
+
console.error(chalk.dim("Run `task0 daemon register` first (set api_url with `task0 profile set api_url <url>` if needed)."));
|
|
1699
1707
|
process.exit(1);
|
|
1700
1708
|
}
|
|
1701
1709
|
return id;
|
|
@@ -5787,10 +5795,20 @@ function fail6(message, code = 1) {
|
|
|
5787
5795
|
function loadRequiredIdentity() {
|
|
5788
5796
|
const identity = readDaemonIdentity();
|
|
5789
5797
|
if (!identity) {
|
|
5790
|
-
fail6(`No daemon identity at ${daemonConfigPath()}. Run \`task0 daemon register
|
|
5798
|
+
fail6(`No daemon identity at ${daemonConfigPath()}. Run \`task0 daemon register\` first (set api_url with \`task0 profile set api_url <url>\` if it isn't already configured).`);
|
|
5791
5799
|
}
|
|
5792
5800
|
return identity;
|
|
5793
5801
|
}
|
|
5802
|
+
function resolveTargetServerUrl() {
|
|
5803
|
+
const url = process.env.TASK0_API_URL?.trim();
|
|
5804
|
+
if (url) return url.replace(/\/$/, "");
|
|
5805
|
+
fail6(
|
|
5806
|
+
`No server URL configured for the active profile.
|
|
5807
|
+
Set it with:
|
|
5808
|
+
task0 profile set api_url <url>
|
|
5809
|
+
\u2026or export TASK0_API_URL for a one-off override.`
|
|
5810
|
+
);
|
|
5811
|
+
}
|
|
5794
5812
|
function serverBase(identity) {
|
|
5795
5813
|
if (identity) return identity.server_url.replace(/\/$/, "");
|
|
5796
5814
|
return (process.env.TASK0_API_URL || "http://127.0.0.1:4318").replace(/\/$/, "");
|
|
@@ -5828,7 +5846,7 @@ function rerunArgv() {
|
|
|
5828
5846
|
return ["task0", ...process.argv.slice(2)].join(" ");
|
|
5829
5847
|
}
|
|
5830
5848
|
var daemonCmd = new Command19("daemon").description("Manage this host as a task0 daemon registered with a central server");
|
|
5831
|
-
daemonCmd.command("register").description("Register this host with
|
|
5849
|
+
daemonCmd.command("register").description("Register this host with the server configured in the active profile, install the autostart service, and start it").option("-n, --name <name>", "Display name for this daemon (defaults to hostname)").option("-t, --token <token>", "API token (apit_...) for registration. Falls back to TASK0_API_TOKEN, then admin token.").option("--force", "Overwrite existing identity if present").option("--system", "Install at the system layer (LaunchDaemons / /etc/systemd/system, requires sudo)").option("--no-install", "Skip installing the autostart service unit").option("--no-start", "Install the service unit but do not start it now").action(async (opts) => {
|
|
5832
5850
|
const scope = opts.system ? "system" : "user";
|
|
5833
5851
|
if (opts.install) {
|
|
5834
5852
|
requireRootIfSystem(scope, rerunArgv());
|
|
@@ -5837,7 +5855,7 @@ daemonCmd.command("register").description("Register this host with a central ser
|
|
|
5837
5855
|
if (existing && !opts.force) {
|
|
5838
5856
|
fail6(`Already registered as ${existing.daemon_id}. Pass --force to re-register.`);
|
|
5839
5857
|
}
|
|
5840
|
-
const base =
|
|
5858
|
+
const base = resolveTargetServerUrl();
|
|
5841
5859
|
let authHeader;
|
|
5842
5860
|
try {
|
|
5843
5861
|
const choice = pickRegisterAuth(opts.token);
|
|
@@ -6666,6 +6684,10 @@ import path31 from "path";
|
|
|
6666
6684
|
import { Command as Command23 } from "commander";
|
|
6667
6685
|
import chalk23 from "chalk";
|
|
6668
6686
|
import yaml10 from "js-yaml";
|
|
6687
|
+
var PROFILE_SCALAR_KEYS = ["api_url"];
|
|
6688
|
+
function isProfileScalarKey(key) {
|
|
6689
|
+
return PROFILE_SCALAR_KEYS.includes(key);
|
|
6690
|
+
}
|
|
6669
6691
|
function fail9(msg) {
|
|
6670
6692
|
console.error(chalk23.red(msg));
|
|
6671
6693
|
process.exit(1);
|
|
@@ -6767,6 +6789,25 @@ profile2.command("use <name>").description("Set the current profile").action((na
|
|
|
6767
6789
|
profile2.command("current").description('Print the current profile name (always succeeds; defaults to "default")').action(() => {
|
|
6768
6790
|
console.log(currentProfileName());
|
|
6769
6791
|
});
|
|
6792
|
+
profile2.command("set <key> <value>").description(`Set a config field on the active profile. Supported keys: ${PROFILE_SCALAR_KEYS.join(", ")}.`).action((key, value) => {
|
|
6793
|
+
if (!isProfileScalarKey(key)) {
|
|
6794
|
+
fail9(`Unknown key "${key}". Supported keys: ${PROFILE_SCALAR_KEYS.join(", ")}.`);
|
|
6795
|
+
}
|
|
6796
|
+
const config = loadConfig();
|
|
6797
|
+
config[key] = value;
|
|
6798
|
+
saveConfig(config);
|
|
6799
|
+
console.log(chalk23.green(`${currentProfileName()}.${key} = ${value}`));
|
|
6800
|
+
});
|
|
6801
|
+
profile2.command("get <key>").description(`Read a config field from the active profile. Supported keys: ${PROFILE_SCALAR_KEYS.join(", ")}.`).action((key) => {
|
|
6802
|
+
if (!isProfileScalarKey(key)) {
|
|
6803
|
+
fail9(`Unknown key "${key}". Supported keys: ${PROFILE_SCALAR_KEYS.join(", ")}.`);
|
|
6804
|
+
}
|
|
6805
|
+
const value = loadConfig()[key];
|
|
6806
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
6807
|
+
process.exit(1);
|
|
6808
|
+
}
|
|
6809
|
+
console.log(value);
|
|
6810
|
+
});
|
|
6770
6811
|
profile2.command("show [name]").description("Show a profile's configuration and daemon registration").action((name) => {
|
|
6771
6812
|
const target = name ?? currentProfileName();
|
|
6772
6813
|
if (!isValidProfileName(target)) {
|
|
@@ -6779,19 +6820,30 @@ profile2.command("show [name]").description("Show a profile's configuration and
|
|
|
6779
6820
|
const current = currentProfileName();
|
|
6780
6821
|
const apiUrl = readProfileApiUrl(target);
|
|
6781
6822
|
const identity = readDaemonAt(dir);
|
|
6823
|
+
const envOverride = target === current ? getActiveProfile()?.envApiUrlOverride : void 0;
|
|
6824
|
+
const effective = envOverride ?? apiUrl;
|
|
6782
6825
|
console.log(`${chalk23.bold(target)}${current === target ? chalk23.green(" (current)") : ""}`);
|
|
6783
6826
|
console.log(` dir: ${dir}`);
|
|
6784
6827
|
console.log(` config: ${path31.join(dir, "config.yml")}`);
|
|
6785
|
-
|
|
6828
|
+
if (envOverride && apiUrl && envOverride !== apiUrl) {
|
|
6829
|
+
console.log(` api_url: ${envOverride} ${chalk23.dim("(TASK0_API_URL env, overrides profile)")}`);
|
|
6830
|
+
console.log(` ${chalk23.dim(`profile: ${apiUrl}`)}`);
|
|
6831
|
+
} else if (envOverride && !apiUrl) {
|
|
6832
|
+
console.log(` api_url: ${envOverride} ${chalk23.dim("(TASK0_API_URL env; profile config.yml is unset)")}`);
|
|
6833
|
+
} else if (apiUrl) {
|
|
6834
|
+
console.log(` api_url: ${apiUrl} ${chalk23.dim("(profile config.yml)")}`);
|
|
6835
|
+
} else {
|
|
6836
|
+
console.log(` api_url: ${chalk23.dim("(unset \u2014 run `task0 profile set api_url <url>`)")}`);
|
|
6837
|
+
}
|
|
6786
6838
|
if (!identity) {
|
|
6787
6839
|
console.log(chalk23.dim(" daemon.json: (not registered yet)"));
|
|
6788
6840
|
return;
|
|
6789
6841
|
}
|
|
6790
6842
|
console.log(` daemon_id: ${identity.daemon_id ?? chalk23.dim("(missing)")}`);
|
|
6791
6843
|
console.log(` daemon.server_url: ${identity.server_url ?? chalk23.dim("(missing)")}`);
|
|
6792
|
-
if (
|
|
6793
|
-
console.log(chalk23.yellow(` warn:
|
|
6794
|
-
console.log(chalk23.dim(` Re-register the daemon to align: task0 --profile ${target} daemon register --
|
|
6844
|
+
if (effective && identity.server_url && effective !== identity.server_url) {
|
|
6845
|
+
console.log(chalk23.yellow(` warn: effective api_url and daemon.json.server_url disagree.`));
|
|
6846
|
+
console.log(chalk23.dim(` Re-register the daemon to align: task0 --profile ${target} daemon register --force`));
|
|
6795
6847
|
}
|
|
6796
6848
|
});
|
|
6797
6849
|
|