life-pulse 2.3.9 → 2.3.11
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 +19 -0
- package/dist/agent.js +14 -2
- package/dist/analyze.d.ts +1 -19
- package/dist/analyze.js +2 -128
- package/dist/cli.js +341 -167
- package/dist/collectors/calendar.js +1 -4
- package/dist/contacts.d.ts +2 -0
- package/dist/contacts.js +54 -0
- package/dist/conversation.js +3 -0
- package/dist/crm.d.ts +1 -0
- package/dist/crm.js +176 -86
- package/dist/ghostty-frames.json +1 -0
- package/dist/installer.d.ts +2 -2
- package/dist/installer.js +55 -24
- package/dist/profile.d.ts +6 -0
- package/dist/profile.js +230 -1
- package/dist/progress.d.ts +1 -0
- package/dist/progress.js +67 -31
- package/dist/prompt-layers.d.ts +17 -0
- package/dist/prompt-layers.js +113 -0
- package/dist/router.d.ts +3 -2
- package/dist/router.js +3 -2
- package/dist/session-progress.d.ts +2 -2
- package/dist/session-progress.js +2 -11
- package/dist/skill-loader.d.ts +1 -1
- package/dist/skill-loader.js +1 -1
- package/dist/sms-gateway.d.ts +6 -11
- package/dist/sms-gateway.js +14 -11
- package/dist/state.d.ts +1 -1
- package/dist/state.js +13 -17
- package/dist/tools.js +1 -3
- package/dist/transport.d.ts +1 -1
- package/dist/transport.js +1 -1
- package/dist/tui.d.ts +4 -3
- package/dist/tui.js +126 -66
- package/dist/tunnel.d.ts +1 -2
- package/dist/tunnel.js +1 -2
- package/dist/ui/app.d.ts +2 -1
- package/dist/ui/app.js +42 -25
- package/dist/ui/progress.d.ts +1 -0
- package/dist/ui/progress.js +75 -35
- package/package.json +4 -3
package/dist/tunnel.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Tailscale Funnel — expose local port as HTTPS to the internet.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* No Twilio — messages go through rply-mac-server's imwebserver (local).
|
|
4
|
+
* Used to expose the local NOX gateway (:19877) for inbound tool calls.
|
|
6
5
|
*
|
|
7
6
|
*/
|
|
8
7
|
/** Check if tailscale CLI is available */
|
package/dist/tunnel.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Tailscale Funnel — expose local port as HTTPS to the internet.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* No Twilio — messages go through rply-mac-server's imwebserver (local).
|
|
4
|
+
* Used to expose the local NOX gateway (:19877) for inbound tool calls.
|
|
6
5
|
*
|
|
7
6
|
*/
|
|
8
7
|
import { execSync, spawn } from 'child_process';
|
package/dist/ui/app.d.ts
CHANGED
|
@@ -21,10 +21,11 @@ export declare function initInk(seedLines?: string[]): void;
|
|
|
21
21
|
export declare function destroy(): void;
|
|
22
22
|
export declare function log(text: string): void;
|
|
23
23
|
export declare function gap(): void;
|
|
24
|
+
export declare function pinLine(text: string): void;
|
|
24
25
|
export declare function showSpinner(label: string): void;
|
|
25
26
|
export declare function updateSpinner(label: string): void;
|
|
26
27
|
export declare function hideSpinner(doneMsg?: string): void;
|
|
27
|
-
export declare function pickCard(card: CardData, num: number): Promise<string>;
|
|
28
|
+
export declare function pickCard(card: CardData, num: number, total?: number): Promise<string>;
|
|
28
29
|
export declare function showProgress(phase: string, done: number, total: number, items: {
|
|
29
30
|
label: string;
|
|
30
31
|
tool?: string;
|
package/dist/ui/app.js
CHANGED
|
@@ -13,10 +13,18 @@ let _update = null;
|
|
|
13
13
|
let _cardResolve = null;
|
|
14
14
|
let _enterResolve = null;
|
|
15
15
|
const INIT = {
|
|
16
|
+
stickyLines: [],
|
|
16
17
|
lines: [], spinner: null,
|
|
17
|
-
card: null, cardNum: 0, cardSel: 0,
|
|
18
|
+
card: null, cardNum: 0, cardTotal: null, cardSel: 0,
|
|
18
19
|
progress: null,
|
|
19
20
|
};
|
|
21
|
+
const MAX_LOG_LINES = 24;
|
|
22
|
+
function appendLines(prev, next) {
|
|
23
|
+
const merged = [...prev, ...next];
|
|
24
|
+
if (merged.length <= MAX_LOG_LINES)
|
|
25
|
+
return merged;
|
|
26
|
+
return merged.slice(merged.length - MAX_LOG_LINES);
|
|
27
|
+
}
|
|
20
28
|
// ─── Components ───────────────────────────────────
|
|
21
29
|
const SpinnerLine = ({ label, frame }) => (_jsxs(Text, { children: [' ', _jsx(Text, { color: "#565f89", children: BAR_CHARS[Math.floor(frame / 3) % BAR_CHARS.length] }), ' ', _jsx(Text, { color: "#565f89", children: label })] }));
|
|
22
30
|
const BAR_W = 20;
|
|
@@ -28,18 +36,24 @@ const Bar = ({ done, total }) => {
|
|
|
28
36
|
const ProgressView = ({ progress, frame }) => {
|
|
29
37
|
const spin = (off = 0) => BAR_CHARS[(Math.floor((frame + off) / 5)) % BAR_CHARS.length];
|
|
30
38
|
if (progress.thinking && !progress.items.length && !progress.total) {
|
|
31
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { children: ' ' }), _jsxs(Text, { children: [' ', _jsx(Text, { color: "#3b4261", children: spin() }), ' ', _jsx(Text, { color: "#565f89", children:
|
|
39
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { children: ' ' }), _jsxs(Text, { children: [' ', _jsx(Text, { color: "#3b4261", children: spin() }), ' ', _jsx(Text, { color: "#565f89", children: progress.phase || 'assembling briefing' })] })] }));
|
|
32
40
|
}
|
|
33
41
|
const { phase, done, total, items } = progress;
|
|
34
42
|
const allDone = done === total && total > 0;
|
|
35
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { children: ' ' }), allDone ? (_jsxs(Text, { children: [' ', _jsx(Text, { color: "#3b4261", children: spin() }), ' ', _jsx(Text, { color: "#565f89", children: phase
|
|
43
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { children: ' ' }), allDone ? (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { children: [' ', _jsx(Text, { color: "#3b4261", children: spin() }), ' ', _jsx(Text, { color: "#565f89", children: phase || 'writing briefing' })] }), items.slice(0, MAX_VIS).map((item, i) => (_jsxs(Text, { children: [' ', _jsx(Text, { color: "#3b4261", children: '·' }), ' ', _jsx(Text, { color: "#3b4261", children: item.label })] }, i)))] })) : total > 0 ? (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { children: [' ', _jsx(Text, { color: "#565f89", children: phase || 'working' }), ' ', _jsx(Bar, { done: done, total: total })] }), items.slice(0, MAX_VIS).map((item, i) => (_jsxs(Text, { children: [' ', _jsx(Text, { color: "#3b4261", children: spin(i) }), ' ', _jsx(Text, { color: "#565f89", children: item.label }), item.tool && _jsxs(Text, { color: "#3b4261", children: [' — ', item.tool] })] }, i))), items.length > MAX_VIS && _jsxs(Text, { color: "#3b4261", children: [' ', "+", items.length - MAX_VIS, " more"] })] })) : null, progress.thinking && total > 0 && !allDone && (_jsxs(Text, { children: [' ', _jsx(Text, { color: "#3b4261", children: spin() }), ' ', _jsx(Text, { color: "#565f89", children: "thinking" })] }))] }));
|
|
36
44
|
};
|
|
37
|
-
const CardView = ({ card, num, sel }) => {
|
|
45
|
+
const CardView = ({ card, num, total, sel }) => {
|
|
38
46
|
const opts = card.options || [];
|
|
39
|
-
|
|
47
|
+
const progressLabel = total && total > 0 ? `${num}/${total}` : String(num);
|
|
48
|
+
const selectedLabel = (opts[sel]?.label || '').trim();
|
|
49
|
+
const selectedAction = selectedLabel || 'continue';
|
|
50
|
+
const hint = opts.length <= 1
|
|
51
|
+
? `[enter to ${selectedAction}]`
|
|
52
|
+
: `[up/down to choose · enter to ${selectedAction}]`;
|
|
53
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { children: ' ' }), _jsxs(Box, { children: [_jsx(Text, { color: "#3b4261", children: ' ┃ ' }), _jsxs(Box, { flexGrow: 1, justifyContent: "space-between", children: [_jsx(Text, { bold: true, color: "#c0caf5", children: "QUESTION" }), _jsx(Text, { color: "#565f89", children: progressLabel })] })] }), _jsxs(Box, { children: [_jsx(Text, { color: "#3b4261", children: ' ┃ ' }), _jsx(Text, { bold: true, color: "#a9b1d6", children: card.title })] }), card.context && (_jsxs(Box, { children: [_jsx(Text, { color: "#3b4261", children: ' ┃ ' }), _jsx(Text, { color: "#565f89", children: card.context })] })), opts.map((opt, i) => {
|
|
40
54
|
const on = i === sel;
|
|
41
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { children:
|
|
42
|
-
}), _jsx(Text, { children: ' ' })] }));
|
|
55
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { children: [_jsx(Text, { color: "#3b4261", children: ' ┃ ' }), _jsx(Text, { color: on ? '#7aa2f7' : '#565f89', children: on ? '◉' : '○' }), _jsx(Text, { children: ' ' }), _jsx(Text, { bold: on, color: on ? '#c0caf5' : '#a9b1d6', children: opt.label })] }), opt.description && (_jsxs(Box, { children: [_jsx(Text, { color: "#3b4261", children: ' ┃ ' }), _jsx(Text, { color: on ? '#565f89' : '#3b4261', children: opt.description })] }))] }, opt.label));
|
|
56
|
+
}), _jsxs(Box, { children: [_jsx(Text, { color: "#3b4261", children: ' ┃ ' }), _jsx(Text, { color: "#565f89", children: hint })] }), _jsx(Text, { children: ' ' })] }));
|
|
43
57
|
};
|
|
44
58
|
// ─── Main App ─────────────────────────────────────
|
|
45
59
|
const App = () => {
|
|
@@ -65,13 +79,14 @@ const App = () => {
|
|
|
65
79
|
const s = stateRef.current;
|
|
66
80
|
if (s.card && s.card.options?.length) {
|
|
67
81
|
const opts = s.card.options;
|
|
82
|
+
const enterPressed = key.return || input === '\r' || input === '\n';
|
|
68
83
|
if (key.upArrow || input === 'k') {
|
|
69
84
|
setState(p => ({ ...p, cardSel: (p.cardSel - 1 + opts.length) % opts.length }));
|
|
70
85
|
}
|
|
71
86
|
else if (key.downArrow || input === 'j') {
|
|
72
87
|
setState(p => ({ ...p, cardSel: (p.cardSel + 1) % opts.length }));
|
|
73
88
|
}
|
|
74
|
-
else if (
|
|
89
|
+
else if (enterPressed || input === ' ') {
|
|
75
90
|
_cardResolve?.(opts[s.cardSel].label);
|
|
76
91
|
_cardResolve = null;
|
|
77
92
|
}
|
|
@@ -93,13 +108,13 @@ const App = () => {
|
|
|
93
108
|
process.exit(0);
|
|
94
109
|
}
|
|
95
110
|
});
|
|
96
|
-
return (_jsxs(Box, { flexDirection: "column", children: [state.lines.map((line, i) => _jsx(Text, { children: line }, i)), state.spinner && _jsx(SpinnerLine, { label: state.spinner, frame: frame }), state.progress && (_jsx(ProgressView, { progress: state.progress, frame: frame })), state.card && state.card.options?.length ? (_jsx(CardView, { card: state.card, num: state.cardNum, sel: state.cardSel })) : null] }));
|
|
111
|
+
return (_jsxs(Box, { flexDirection: "column", children: [state.stickyLines.map((line, i) => _jsx(Text, { children: line }, `sticky-${i}`)), state.lines.map((line, i) => _jsx(Text, { children: line }, i)), state.spinner && _jsx(SpinnerLine, { label: state.spinner, frame: frame }), state.progress && (_jsx(ProgressView, { progress: state.progress, frame: frame })), state.card && state.card.options?.length ? (_jsx(CardView, { card: state.card, num: state.cardNum, total: state.cardTotal, sel: state.cardSel })) : null] }));
|
|
97
112
|
};
|
|
98
113
|
// ─── Singleton ────────────────────────────────────
|
|
99
114
|
let _inst = null;
|
|
100
115
|
let _started = false;
|
|
101
116
|
const _origLog = console.log.bind(console);
|
|
102
|
-
let
|
|
117
|
+
let _seedStickyLines = [];
|
|
103
118
|
function ensureStarted() {
|
|
104
119
|
if (_started)
|
|
105
120
|
return;
|
|
@@ -107,27 +122,26 @@ function ensureStarted() {
|
|
|
107
122
|
process.stdout.write('\x1B[2J\x1B[H'); // clear screen
|
|
108
123
|
process.stdout.write('\x1B[?25l'); // hide cursor
|
|
109
124
|
_inst = inkRender(React.createElement(App));
|
|
110
|
-
// Seed
|
|
111
|
-
if (
|
|
112
|
-
const lines =
|
|
113
|
-
|
|
125
|
+
// Seed pinned lines (e.g. greeting from intro)
|
|
126
|
+
if (_seedStickyLines.length) {
|
|
127
|
+
const lines = _seedStickyLines;
|
|
128
|
+
_seedStickyLines = [];
|
|
114
129
|
// Small delay to let React mount before pushing state
|
|
115
130
|
setTimeout(() => {
|
|
116
|
-
_update?.(p => ({ ...p,
|
|
131
|
+
_update?.(p => ({ ...p, stickyLines: lines }));
|
|
117
132
|
}, 50);
|
|
118
133
|
}
|
|
119
134
|
// Redirect console.log through Ink
|
|
120
135
|
console.log = (...args) => {
|
|
121
136
|
const text = args.map(a => typeof a === 'string' ? a : String(a)).join(' ');
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
}
|
|
137
|
+
const next = text.split('\n');
|
|
138
|
+
_update?.(p => ({ ...p, lines: appendLines(p.lines, next) }));
|
|
125
139
|
};
|
|
126
140
|
}
|
|
127
141
|
// ─── Exports ──────────────────────────────────────
|
|
128
142
|
export function initInk(seedLines) {
|
|
129
143
|
if (seedLines)
|
|
130
|
-
|
|
144
|
+
_seedStickyLines = seedLines;
|
|
131
145
|
ensureStarted();
|
|
132
146
|
}
|
|
133
147
|
export function destroy() {
|
|
@@ -142,11 +156,14 @@ export function log(text) {
|
|
|
142
156
|
_origLog(text);
|
|
143
157
|
return;
|
|
144
158
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
}
|
|
159
|
+
const next = text.split('\n');
|
|
160
|
+
_update?.(p => ({ ...p, lines: appendLines(p.lines, next) }));
|
|
148
161
|
}
|
|
149
162
|
export function gap() { log(''); }
|
|
163
|
+
export function pinLine(text) {
|
|
164
|
+
ensureStarted();
|
|
165
|
+
_update?.(p => ({ ...p, stickyLines: [...p.stickyLines, text] }));
|
|
166
|
+
}
|
|
150
167
|
// ── Spinner ──
|
|
151
168
|
export function showSpinner(label) {
|
|
152
169
|
ensureStarted();
|
|
@@ -161,7 +178,7 @@ export function hideSpinner(doneMsg) {
|
|
|
161
178
|
log(` ${C.dim(doneMsg)}`);
|
|
162
179
|
}
|
|
163
180
|
// ── Card picker ──
|
|
164
|
-
export async function pickCard(card, num) {
|
|
181
|
+
export async function pickCard(card, num, total) {
|
|
165
182
|
ensureStarted();
|
|
166
183
|
if (card.fyi || !card.options?.length) {
|
|
167
184
|
log(` ${C.dim('·')} ${card.title}${card.context ? ' ' + C.dim(card.context) : ''}`);
|
|
@@ -169,13 +186,13 @@ export async function pickCard(card, num) {
|
|
|
169
186
|
}
|
|
170
187
|
return new Promise(resolve => {
|
|
171
188
|
_cardResolve = (pick) => {
|
|
172
|
-
_update?.(p => ({ ...p, card: null, cardSel: 0 }));
|
|
189
|
+
_update?.(p => ({ ...p, card: null, cardSel: 0, cardTotal: null }));
|
|
173
190
|
const t = card.title.length > 50 ? card.title.slice(0, 49) + '…' : card.title;
|
|
174
191
|
log(` ${C.dim(t)} ${C.faint('→')} ${C.bright(pick)}`);
|
|
175
192
|
log('');
|
|
176
193
|
resolve(pick);
|
|
177
194
|
};
|
|
178
|
-
_update?.(p => ({ ...p, card, cardNum: num, cardSel: 0 }));
|
|
195
|
+
_update?.(p => ({ ...p, card, cardNum: num, cardTotal: total ?? null, cardSel: 0 }));
|
|
179
196
|
});
|
|
180
197
|
}
|
|
181
198
|
// ── Progress ──
|
package/dist/ui/progress.d.ts
CHANGED
package/dist/ui/progress.js
CHANGED
|
@@ -5,30 +5,51 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { showProgress, hideProgress } from './app.js';
|
|
7
7
|
const LABEL = {
|
|
8
|
-
search_all_messages: '
|
|
9
|
-
get_conversation: '
|
|
10
|
-
profile_contact: '
|
|
11
|
-
get_messages: '
|
|
12
|
-
get_unanswered_messages: '
|
|
13
|
-
get_screen_time: '
|
|
14
|
-
get_browsing: '
|
|
15
|
-
get_calls: '
|
|
16
|
-
scan_sources: '
|
|
17
|
-
lookup_contact: '
|
|
18
|
-
get_email_summary: '
|
|
19
|
-
get_git_activity: '
|
|
20
|
-
get_recent_files: '
|
|
21
|
-
get_shell_history: '
|
|
22
|
-
get_notes: '
|
|
23
|
-
get_claude_history: '
|
|
24
|
-
get_chatgpt_history: '
|
|
25
|
-
get_interests_for_plans: '
|
|
26
|
-
get_calendar: '
|
|
27
|
-
get_reminders: '
|
|
28
|
-
get_notifications: '
|
|
29
|
-
discover_platforms: '
|
|
30
|
-
generate_archetype: '
|
|
31
|
-
search_emails: '
|
|
8
|
+
search_all_messages: 'messages: keyword matches',
|
|
9
|
+
get_conversation: 'messages: thread context',
|
|
10
|
+
profile_contact: 'contact profile',
|
|
11
|
+
get_messages: 'messages: recent threads',
|
|
12
|
+
get_unanswered_messages: 'messages: waiting on reply',
|
|
13
|
+
get_screen_time: 'screen time',
|
|
14
|
+
get_browsing: 'browser history',
|
|
15
|
+
get_calls: 'call history',
|
|
16
|
+
scan_sources: 'source availability',
|
|
17
|
+
lookup_contact: 'contact lookup',
|
|
18
|
+
get_email_summary: 'mail summary',
|
|
19
|
+
get_git_activity: 'git activity',
|
|
20
|
+
get_recent_files: 'recent files',
|
|
21
|
+
get_shell_history: 'shell history',
|
|
22
|
+
get_notes: 'notes',
|
|
23
|
+
get_claude_history: 'claude chats',
|
|
24
|
+
get_chatgpt_history: 'chatgpt chats',
|
|
25
|
+
get_interests_for_plans: 'planning signals',
|
|
26
|
+
get_calendar: 'calendar (next 7d)',
|
|
27
|
+
get_reminders: 'reminders',
|
|
28
|
+
get_notifications: 'notifications',
|
|
29
|
+
discover_platforms: 'platform detection',
|
|
30
|
+
generate_archetype: 'profile synthesis',
|
|
31
|
+
search_emails: 'mail search',
|
|
32
|
+
};
|
|
33
|
+
const TOOL_SOURCE = {
|
|
34
|
+
scan_sources: 'source index',
|
|
35
|
+
get_messages: 'messages',
|
|
36
|
+
get_unanswered_messages: 'messages',
|
|
37
|
+
get_conversation: 'messages',
|
|
38
|
+
search_all_messages: 'messages',
|
|
39
|
+
get_calendar: 'calendar',
|
|
40
|
+
get_calls: 'calls',
|
|
41
|
+
get_email_summary: 'mail',
|
|
42
|
+
search_emails: 'mail',
|
|
43
|
+
get_claude_history: 'claude',
|
|
44
|
+
get_chatgpt_history: 'chatgpt',
|
|
45
|
+
get_notes: 'notes',
|
|
46
|
+
get_recent_files: 'files',
|
|
47
|
+
get_shell_history: 'shell',
|
|
48
|
+
get_git_activity: 'git',
|
|
49
|
+
get_screen_time: 'screen time',
|
|
50
|
+
get_browsing: 'browser',
|
|
51
|
+
get_notifications: 'notifications',
|
|
52
|
+
get_reminders: 'reminders',
|
|
32
53
|
};
|
|
33
54
|
export class InkProgress {
|
|
34
55
|
tools = [];
|
|
@@ -36,6 +57,15 @@ export class InkProgress {
|
|
|
36
57
|
_thinking = false;
|
|
37
58
|
_paused = false;
|
|
38
59
|
s(name) { return LABEL[name] || name; }
|
|
60
|
+
phaseForTools(active) {
|
|
61
|
+
const sources = [...new Set(active.map(t => TOOL_SOURCE[t.name] || 'other'))];
|
|
62
|
+
if (!sources.length)
|
|
63
|
+
return 'scanning sources';
|
|
64
|
+
const lead = sources.slice(0, 2).join(' + ');
|
|
65
|
+
return sources.length > 2
|
|
66
|
+
? `scanning ${lead} +${sources.length - 2}`
|
|
67
|
+
: `scanning ${lead}`;
|
|
68
|
+
}
|
|
39
69
|
paint() {
|
|
40
70
|
if (this._paused)
|
|
41
71
|
return;
|
|
@@ -43,14 +73,28 @@ export class InkProgress {
|
|
|
43
73
|
const workersDone = this.workers.filter(w => w.done).length;
|
|
44
74
|
const activeWorkers = this.workers.filter(w => !w.done);
|
|
45
75
|
if (this.workers.length > 0) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
76
|
+
if (activeWorkers.length > 0) {
|
|
77
|
+
showProgress(`investigating ${activeWorkers.length} item${activeWorkers.length === 1 ? '' : 's'}`, workersDone, this.workers.length, activeWorkers.map(w => ({
|
|
78
|
+
label: w.label,
|
|
79
|
+
tool: w.tool ? this.s(w.tool) : undefined,
|
|
80
|
+
})), this._thinking);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
const doneLabels = this.workers
|
|
84
|
+
.filter(w => w.done && !w.failed)
|
|
85
|
+
.slice(-4)
|
|
86
|
+
.map(w => ({ label: w.label }));
|
|
87
|
+
showProgress('writing briefing', workersDone, this.workers.length, doneLabels, this._thinking);
|
|
88
|
+
}
|
|
50
89
|
}
|
|
51
90
|
else if (this.tools.length > 0) {
|
|
52
91
|
const active = this.tools.filter(t => !t.done);
|
|
53
|
-
|
|
92
|
+
if (active.length > 0) {
|
|
93
|
+
showProgress(this.phaseForTools(active), toolsDone, this.tools.length, active.map(t => ({ label: this.s(t.name) })), this._thinking);
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
showProgress('analyzing', toolsDone, this.tools.length, [], this._thinking);
|
|
97
|
+
}
|
|
54
98
|
}
|
|
55
99
|
else if (this._thinking) {
|
|
56
100
|
showProgress('', 0, 0, [], true);
|
|
@@ -71,8 +115,7 @@ export class InkProgress {
|
|
|
71
115
|
const t = this.tools.find(t => t.name === name && !t.done);
|
|
72
116
|
if (t)
|
|
73
117
|
t.done = true;
|
|
74
|
-
|
|
75
|
-
setTimeout(() => this.paint(), 400);
|
|
118
|
+
this.paint();
|
|
76
119
|
}
|
|
77
120
|
workerStart(id, label) {
|
|
78
121
|
this._thinking = false;
|
|
@@ -114,9 +157,6 @@ export class InkProgress {
|
|
|
114
157
|
}
|
|
115
158
|
pause() { this._paused = true; hideProgress(); }
|
|
116
159
|
resume() { this._paused = false; this.paint(); }
|
|
117
|
-
stop() {
|
|
118
|
-
// Let the final state linger so it doesn't vanish instantly
|
|
119
|
-
setTimeout(() => hideProgress(), 800);
|
|
120
|
-
}
|
|
160
|
+
stop() { hideProgress(); }
|
|
121
161
|
clear() { hideProgress(); }
|
|
122
162
|
}
|
package/package.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "life-pulse",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.11",
|
|
4
4
|
"description": "macOS life diagnostic — reads local data sources, generates actionable insights",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"test": "echo \"Error: no test specified\" && exit 1",
|
|
8
|
-
"build": "tsc && chmod +x dist/cli.js",
|
|
8
|
+
"build": "tsc && cp src/ghostty-frames.json dist/ && chmod +x dist/cli.js",
|
|
9
9
|
"dev": "tsx src/cli.ts",
|
|
10
10
|
"start": "node dist/cli.js",
|
|
11
11
|
"daemon": "node dist/cli.js --daemon",
|
|
12
12
|
"check": "node dist/cli.js --check",
|
|
13
13
|
"prepublishOnly": "npm run build",
|
|
14
|
-
"postinstall": "node -e \"console.log('\\n life-pulse installed.\\n Run: npx life-pulse --setup\\n Or: npx life-pulse --install (daemon + morning brief)\\n')\""
|
|
14
|
+
"postinstall": "node -e \"const fs=require('fs');const os=require('os');const path=require('path');const base=path.join(os.homedir(),'.life-pulse');const soul=path.join(base,'SOUL.md');const memory=path.join(base,'MEMORY.md');const soulTemplate='# NOX Identity\\n\\n- You are NOX, the user\\'s always-on operator.\\n- Voice: direct, warm, sharp, no corporate language.\\n- Prefer concrete next actions over abstract advice.\\n- Never invent facts. If signal is weak, say less.\\n- Keep output compact unless explicitly asked for depth.\\n- In text replies, sound human and conversational.\\n- Prioritize reputation, promises, and momentum.\\n';const memoryTemplate='# Persistent Memory\\n\\n## Operator\\n- Name: <auto-detected at runtime>\\n\\n## Preferences\\n- Prefer terse, high-signal summaries.\\n- Focus on what needs action now.\\n\\n## Ongoing Context\\n- Keep this file updated with durable context that should persist across turns.\\n';try{fs.mkdirSync(base,{recursive:true});if(!fs.existsSync(soul))fs.writeFileSync(soul,soulTemplate,'utf-8');if(!fs.existsSync(memory))fs.writeFileSync(memory,memoryTemplate,'utf-8');}catch{}console.log('\\n life-pulse installed.\\n Run: npx life-pulse --setup\\n Or: npx life-pulse --install (daemon + morning brief)\\n')\""
|
|
15
15
|
},
|
|
16
16
|
"keywords": [
|
|
17
17
|
"macos",
|
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
"bplist-parser": "^0.3.2",
|
|
45
45
|
"chalk": "^5.6.2",
|
|
46
46
|
"dayjs": "^1.11.19",
|
|
47
|
+
"figlet": "^1.10.0",
|
|
47
48
|
"ink": "^6.8.0",
|
|
48
49
|
"react": "^19.2.4",
|
|
49
50
|
"zod": "^4.3.6"
|