taskair-cli 1.0.8 → 1.0.10

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 CHANGED
@@ -28,10 +28,7 @@ Run the configuration command and follow the prompt to open the browser for auth
28
28
  taskair config
29
29
  ```
30
30
 
31
- You will be prompted to enter:
32
- * **API URL**: The URL of your running TaskAir server (e.g., `http://localhost:3001` or your production domain).
33
-
34
- After pressing Enter, a web browser window will open automatically. Complete your sign-in or enter your Master Password on the website to link your CLI terminal.
31
+ After running the command, a web browser window will open automatically. Complete your sign-in or enter your Master Password on the website to link your CLI terminal. The API URL is automatically preconfigured to point to our production endpoint (`https://api-taskair.vercel.app`).
35
32
 
36
33
  ### 2. Verify Session
37
34
 
package/dist/index.js CHANGED
@@ -69,7 +69,7 @@ function readCredentials() {
69
69
  const raw = parseIni(content);
70
70
  const rawExpires = raw.expires_at ? parseInt(raw.expires_at, 10) : void 0;
71
71
  return {
72
- api_url: raw.api_url || "http://localhost:3001",
72
+ api_url: raw.api_url || "https://api-taskair.vercel.app",
73
73
  email: raw.email || "",
74
74
  access_token: raw.access_token || void 0,
75
75
  refresh_token: raw.refresh_token || void 0,
@@ -383,35 +383,16 @@ function openBrowser(url) {
383
383
  const cmd = process.platform === "win32" ? `start "" "${url}"` : `${start} "${url}"`;
384
384
  exec(cmd);
385
385
  }
386
- function ConfigUI({ initialApiUrl }) {
386
+ function ConfigUI() {
387
387
  const { exit } = useApp();
388
- const [stage, setStage] = useState4("input_api_url");
389
- const [apiUrl, setApiUrl] = useState4(initialApiUrl);
390
- const [currentInput, setCurrentInput] = useState4(initialApiUrl);
388
+ const [stage, setStage] = useState4("waiting_for_browser");
389
+ const apiUrl = "https://api-taskair.vercel.app";
391
390
  const [port, setPort] = useState4(0);
392
391
  const [errorMsg, setErrorMsg] = useState4("");
393
392
  const [authDetails, setAuthDetails] = useState4(null);
394
393
  useInput((input, key) => {
395
- if (stage === "input_api_url") {
396
- if (key.return) {
397
- if (!currentInput.trim()) {
398
- setErrorMsg("API URL cannot be empty");
399
- return;
400
- }
401
- setErrorMsg("");
402
- setApiUrl(currentInput.trim());
403
- setStage("waiting_for_browser");
404
- } else if (key.backspace || key.delete) {
405
- setCurrentInput((v) => v.slice(0, -1));
406
- } else if (key.escape) {
407
- exit();
408
- } else {
409
- setCurrentInput((v) => v + input);
410
- }
411
- } else {
412
- if (key.escape) {
413
- exit();
414
- }
394
+ if (key.escape) {
395
+ exit();
415
396
  }
416
397
  });
417
398
  useEffect4(() => {
@@ -656,18 +637,7 @@ function ConfigUI({ initialApiUrl }) {
656
637
  }, [stage, authDetails, apiUrl]);
657
638
  return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", padding: 1, children: [
658
639
  /* @__PURE__ */ jsx4(AsciiHeader, {}),
659
- /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", marginBottom: 1, children: [
660
- /* @__PURE__ */ jsx4(Text4, { color: "cyan", bold: true, children: "\u2726 Configure TaskAir" }),
661
- stage === "input_api_url" && /* @__PURE__ */ jsx4(Text4, { color: "gray", children: "Enter the API URL of your TaskAir instance. Press Enter to confirm." })
662
- ] }),
663
- stage === "input_api_url" && /* @__PURE__ */ jsxs4(Box4, { children: [
664
- /* @__PURE__ */ jsx4(Text4, { color: "cyan", bold: true, children: "\u2192 " }),
665
- /* @__PURE__ */ jsx4(Text4, { color: "white", children: "API URL: " }),
666
- /* @__PURE__ */ jsxs4(Text4, { color: "cyan", children: [
667
- currentInput,
668
- /* @__PURE__ */ jsx4(Text4, { color: "white", children: "\u258C" })
669
- ] })
670
- ] }),
640
+ /* @__PURE__ */ jsx4(Box4, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsx4(Text4, { color: "cyan", bold: true, children: "\u2726 Configure TaskAir" }) }),
671
641
  stage === "waiting_for_browser" && /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", gap: 0.5, children: [
672
642
  /* @__PURE__ */ jsxs4(Text4, { color: "cyan", children: [
673
643
  "\u2713 API URL set to: ",
@@ -689,17 +659,14 @@ function ConfigUI({ initialApiUrl }) {
689
659
  ] }),
690
660
  stage === "success" && /* @__PURE__ */ jsx4(Box4, { marginTop: 1, children: /* @__PURE__ */ jsx4(StatusBadge, { type: "success", message: "Configuration saved successfully! E2E Encryption Active." }) }),
691
661
  stage === "error" && /* @__PURE__ */ jsx4(Box4, { marginTop: 1, children: /* @__PURE__ */ jsx4(StatusBadge, { type: "error", message: errorMsg }) }),
692
- (stage === "input_api_url" || stage === "waiting_for_browser") && /* @__PURE__ */ jsx4(Box4, { marginTop: 1, children: /* @__PURE__ */ jsx4(Text4, { color: "gray", dimColor: true, children: "Press Esc to cancel" }) })
662
+ stage === "waiting_for_browser" && /* @__PURE__ */ jsx4(Box4, { marginTop: 1, children: /* @__PURE__ */ jsx4(Text4, { color: "gray", dimColor: true, children: "Press Esc to cancel" }) })
693
663
  ] });
694
664
  }
695
665
  function registerConfig(program2) {
696
666
  program2.command("config").alias("configure").description("Authenticate and configure CLI via browser").action(async () => {
697
- const existing = readCredentials();
698
667
  const { render } = await import("ink");
699
668
  render(
700
- React4.createElement(ConfigUI, {
701
- initialApiUrl: existing?.api_url ?? "http://localhost:3001"
702
- })
669
+ React4.createElement(ConfigUI)
703
670
  );
704
671
  });
705
672
  }
@@ -719,7 +686,7 @@ function LoginUI() {
719
686
  const [errorMsg, setErrorMsg] = useState5("");
720
687
  useEffect5(() => {
721
688
  if (stage === "loading") {
722
- const apiUrl = creds?.api_url ?? "http://localhost:3001";
689
+ const apiUrl = creds?.api_url ?? "https://api-taskair.vercel.app";
723
690
  apiLogin(apiUrl, email, password).then(async (res) => {
724
691
  if (res.success && res.data) {
725
692
  const accessToken = res.data.access_token;
@@ -2169,7 +2136,7 @@ import { Box as Box16, Text as Text16, useApp as useApp11 } from "ink";
2169
2136
  import { exec as exec2 } from "child_process";
2170
2137
 
2171
2138
  // src/lib/version.ts
2172
- var CLI_VERSION = "1.0.7";
2139
+ var CLI_VERSION = "1.0.10";
2173
2140
 
2174
2141
  // src/commands/upgrade.tsx
2175
2142
  import { jsx as jsx16, jsxs as jsxs16 } from "react/jsx-runtime";
package/package.json CHANGED
@@ -1,13 +1,14 @@
1
1
  {
2
2
  "name": "taskair-cli",
3
- "version": "1.0.8",
3
+ "version": "1.0.10",
4
4
  "description": "Space-themed, privacy-first task management CLI with E2E encryption",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "taskair": "dist/index.js"
8
8
  },
9
9
  "files": [
10
- "dist"
10
+ "dist",
11
+ "scripts"
11
12
  ],
12
13
  "publishConfig": {
13
14
  "access": "public"
@@ -37,7 +38,8 @@
37
38
  "build": "tsup src/index.ts --format esm --dts --out-dir dist --shims",
38
39
  "start": "node dist/index.js",
39
40
  "lint": "tsc --noEmit",
40
- "taskair": "node --import tsx/esm src/index.ts"
41
+ "taskair": "node --import tsx/esm src/index.ts",
42
+ "postinstall": "node scripts/postinstall.js"
41
43
  },
42
44
  "dependencies": {
43
45
  "chalk": "^5.3.0",
@@ -0,0 +1,168 @@
1
+ import readline from 'readline';
2
+
3
+ const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
4
+
5
+ const SEQUENCE = [
6
+ { type: 'divider' },
7
+ {
8
+ type: 'bar',
9
+ labels: ['Scanning…', 'Analysing…', 'Detecting…', 'Profiling…'],
10
+ icons: ['✦', '◆', '✶', '❋', '✸'],
11
+ duration: 3000,
12
+ tokenTarget: 0.6, // shows "0.6k" counter
13
+ showPercent: true,
14
+ },
15
+ {
16
+ type: 'lines',
17
+ lines: ['New Role Detected', 'New Team Detected', 'New Challenges'],
18
+ },
19
+ { type: 'divider' },
20
+ {
21
+ type: 'bar',
22
+ labels: ['Booting…', 'Loading…', 'Preparing…', 'Initializing…'],
23
+ icons: ['✦', '◆', '✶', '❋', '✸'],
24
+ duration: 3000,
25
+ showPercent: false, // no percent, no tokens — clean spinner
26
+ },
27
+ { type: 'message', text: "Let's build something great 🚀" },
28
+ { type: 'divider' },
29
+ {
30
+ type: 'bar',
31
+ labels: ['Syncing…', 'Configuring…', 'Setting up…', 'Onboarding…'],
32
+ icons: ['◈', '◉', '⬡', '⬢', '◍'],
33
+ duration: 3000,
34
+ tokenTarget: 0.8, // tokens but no percent
35
+ showPercent: false,
36
+ },
37
+ ];
38
+
39
+ const BG_COLOR = '\x1b[48;2;15;14;23m';
40
+ const RESET = '\x1b[0m';
41
+
42
+ function stripAnsi(str) {
43
+ return str.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, '');
44
+ }
45
+
46
+ function printLine(contentStr = '') {
47
+ const rawLen = stripAnsi(contentStr).length;
48
+ const totalWidth = 52;
49
+ const paddingLeft = 4;
50
+ const paddingRight = Math.max(0, totalWidth - paddingLeft - rawLen);
51
+ const leftSpaces = ' '.repeat(paddingLeft);
52
+ const rightSpaces = ' '.repeat(paddingRight);
53
+ console.log(`${BG_COLOR}${leftSpaces}${contentStr}${rightSpaces}${RESET}`);
54
+ }
55
+
56
+ function printLineInPlace(contentStr) {
57
+ const rawLen = stripAnsi(contentStr).length;
58
+ const totalWidth = 52;
59
+ const paddingLeft = 4;
60
+ const paddingRight = Math.max(0, totalWidth - paddingLeft - rawLen);
61
+ const leftSpaces = ' '.repeat(paddingLeft);
62
+ const rightSpaces = ' '.repeat(paddingRight);
63
+ process.stdout.write(`\r${BG_COLOR}${leftSpaces}${contentStr}${rightSpaces}${RESET}`);
64
+ }
65
+
66
+ async function drawDivider() {
67
+ const line = '─'.repeat(44);
68
+ const dividerStr = `\x1b[38;2;54;49;69m${line}\x1b[0m`;
69
+ printLine(dividerStr);
70
+ await delay(80);
71
+ }
72
+
73
+ async function typeLines(lines) {
74
+ for (const line of lines) {
75
+ for (let i = 1; i <= line.length; i++) {
76
+ const textSoFar = line.slice(0, i);
77
+ const cursor = i < line.length ? '▊' : '';
78
+ const contentStr = `\x1b[38;2;230;230;235m${textSoFar}${cursor}\x1b[0m`;
79
+ printLineInPlace(contentStr);
80
+ await delay(40);
81
+ }
82
+ process.stdout.write('\n');
83
+ await delay(200);
84
+ }
85
+ }
86
+
87
+ async function printMessage(text) {
88
+ const contentStr = `\x1b[1m\x1b[38;2;160;130;255m${text}\x1b[0m`;
89
+ printLine(contentStr);
90
+ await delay(400);
91
+ }
92
+
93
+ async function runProgressBar(phase) {
94
+ const { labels, icons, duration, tokenTarget, showPercent = true } = phase;
95
+ const startTime = Date.now();
96
+
97
+ while (true) {
98
+ const elapsed = Date.now() - startTime;
99
+ const progress = Math.min(1, elapsed / duration);
100
+
101
+ const labelIdx = Math.min(
102
+ labels.length - 1,
103
+ Math.floor(progress * labels.length)
104
+ );
105
+ const label = labels[labelIdx];
106
+
107
+ const iconIdx = Math.floor((Date.now() / 150) % icons.length);
108
+ const icon = icons[iconIdx];
109
+
110
+ const barWidth = 16;
111
+ const filledWidth = Math.floor(progress * barWidth);
112
+ const emptyWidth = barWidth - filledWidth;
113
+ const filledStr = `\x1b[38;2;160;130;255m${'█'.repeat(filledWidth)}\x1b[0m`;
114
+ const emptyStr = `\x1b[38;2;54;49;69m${'░'.repeat(emptyWidth)}\x1b[0m`;
115
+ const barStr = `\x1b[38;2;54;49;69m[\x1b[0m${filledStr}${emptyStr}\x1b[38;2;54;49;69m]\x1b[0m`;
116
+
117
+ let suffix = '';
118
+ if (showPercent) {
119
+ const pct = Math.round(progress * 100);
120
+ suffix += ` \x1b[38;2;160;130;255m${pct}%\x1b[0m`;
121
+ }
122
+
123
+ if (tokenTarget !== undefined) {
124
+ const currentTokens = (progress * tokenTarget).toFixed(1);
125
+ suffix += ` \x1b[38;2;210;190;255m ${currentTokens}k tokens\x1b[0m`;
126
+ }
127
+
128
+ const iconColor = `\x1b[38;2;160;130;255m`;
129
+ const labelColor = `\x1b[1m\x1b[38;2;255;255;255m`;
130
+ const output = `${iconColor}${icon}\x1b[0m ${labelColor}${label.padEnd(14)}\x1b[0m${barStr}${suffix}`;
131
+
132
+ printLineInPlace(output);
133
+
134
+ if (progress >= 1) {
135
+ process.stdout.write('\n');
136
+ break;
137
+ }
138
+
139
+ await delay(80);
140
+ }
141
+ }
142
+
143
+ async function run() {
144
+ console.log('\n\x1b[1m\x1b[38;2;160;130;255m✦ Preparing TaskAir CLI Environment... ✦\x1b[0m\n');
145
+
146
+ printLine();
147
+ printLine();
148
+
149
+ for (const step of SEQUENCE) {
150
+ if (step.type === 'divider') {
151
+ await drawDivider();
152
+ } else if (step.type === 'bar') {
153
+ await runProgressBar(step);
154
+ await delay(150);
155
+ } else if (step.type === 'lines') {
156
+ await typeLines(step.lines);
157
+ } else if (step.type === 'message') {
158
+ await printMessage(step.text);
159
+ }
160
+ }
161
+
162
+ printLine();
163
+ printLine();
164
+
165
+ console.log();
166
+ }
167
+
168
+ run();