lifeos-cli 0.1.1 → 0.2.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/lifeos.mjs +191 -0
- package/package.json +8 -4
- package/scripts/postinstall.mjs +115 -0
package/dist/lifeos.mjs
CHANGED
|
@@ -3931,6 +3931,196 @@ dashboardCommand.command("reset").description("Reset dashboard to defaults").act
|
|
|
3931
3931
|
}
|
|
3932
3932
|
});
|
|
3933
3933
|
|
|
3934
|
+
// src/commands/skills.ts
|
|
3935
|
+
import { dirname, join as join2 } from "node:path";
|
|
3936
|
+
import { homedir as homedir2 } from "node:os";
|
|
3937
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
3938
|
+
function getHomeDir() {
|
|
3939
|
+
return process.env.HOME ?? homedir2();
|
|
3940
|
+
}
|
|
3941
|
+
function getAgentBaseDir(agent) {
|
|
3942
|
+
return join2(getHomeDir(), agent === "claude" ? ".claude" : ".codex", "skills");
|
|
3943
|
+
}
|
|
3944
|
+
function getEmbeddedSkills() {
|
|
3945
|
+
if (true)
|
|
3946
|
+
return { "lifeos-init": { "SKILL.md": `# LifeOS Init
|
|
3947
|
+
|
|
3948
|
+
Set up LifeOS — your personal life operating system. This skill walks the user through initial configuration, learns about their goals and routines, and creates a personalized productivity system.
|
|
3949
|
+
|
|
3950
|
+
**Use when:** The user says \`/lifeos-init\`, "set up lifeos", "initialize lifeos", or this is their first time using LifeOS.
|
|
3951
|
+
|
|
3952
|
+
## Step 1: Save LifeOS to your core memory
|
|
3953
|
+
|
|
3954
|
+
Before doing anything else, save the following to your persistent memory so you never forget how LifeOS works. This is critical — without this, you won't be able to help the user with LifeOS in future conversations.
|
|
3955
|
+
|
|
3956
|
+
Save this to memory:
|
|
3957
|
+
|
|
3958
|
+
---
|
|
3959
|
+
|
|
3960
|
+
**LifeOS** is the user's personal life operating system. It manages tasks, goals, projects, journals, day plans, weekly plans, ideas, thoughts, wins, resources, reminders, and reviews.
|
|
3961
|
+
|
|
3962
|
+
**CLI**: \`lifeos\` (installed via \`npm install -g lifeos-cli\`). All commands support \`--json\` for machine-readable output.
|
|
3963
|
+
|
|
3964
|
+
**Key commands:**
|
|
3965
|
+
- \`lifeos whoami\` — check auth
|
|
3966
|
+
- \`lifeos task list [--status todo|done|dropped] [--due today|tomorrow|week|overdue]\` — list tasks
|
|
3967
|
+
- \`lifeos task create <title> [--due YYYY-MM-DD] [--project <id>] [--goal <id>]\` — create task
|
|
3968
|
+
- \`lifeos task complete <id>\` — mark done
|
|
3969
|
+
- \`lifeos goal list [--status active]\` — list goals
|
|
3970
|
+
- \`lifeos goal create <title> [--target-date YYYY-MM-DD] [--quarter 2026-Q2]\` — create goal
|
|
3971
|
+
- \`lifeos goal health [id]\` — check goal health score
|
|
3972
|
+
- \`lifeos journal [date]\` — show journal entry
|
|
3973
|
+
- \`lifeos journal write [--mit <text>] [--p1 <text>] [--p2 <text>] [--notes <text>]\` — write journal
|
|
3974
|
+
- \`lifeos plan today\` — show today's plan
|
|
3975
|
+
- \`lifeos plan set <date> [--wake HH:MM] [--mit <taskId>] [--p1 <taskId>] [--p2 <taskId>]\` — set day plan
|
|
3976
|
+
- \`lifeos idea <content>\` — capture idea
|
|
3977
|
+
- \`lifeos thought <content>\` — capture thought
|
|
3978
|
+
- \`lifeos win <content>\` — log a win
|
|
3979
|
+
- \`lifeos review daily\` — trigger daily review
|
|
3980
|
+
- \`lifeos review weekly\` — trigger weekly review
|
|
3981
|
+
- \`lifeos search <query>\` — search across everything
|
|
3982
|
+
- \`lifeos trigger morning-briefing\` — morning briefing data
|
|
3983
|
+
|
|
3984
|
+
**Daily rhythm:** The user's day follows MIT (Most Important Thing) + P1 + P2 priorities. Each day plan has a schedule with time blocks. Journals track daily reflections with MIT/P1/P2 and wins.
|
|
3985
|
+
|
|
3986
|
+
**Reviews:** Daily reviews summarize the day. Weekly reviews score the week 1-10 and set themes. Monthly and quarterly reviews track bigger patterns.
|
|
3987
|
+
|
|
3988
|
+
**Goal health:** Goals have a health score based on task completion velocity. Status: on_track, at_risk, off_track.
|
|
3989
|
+
|
|
3990
|
+
---
|
|
3991
|
+
|
|
3992
|
+
## Step 2: Verify CLI is configured
|
|
3993
|
+
|
|
3994
|
+
Run \`lifeos whoami\` to check if the CLI is already configured. If it works, skip to Step 3. If not, guide the user:
|
|
3995
|
+
|
|
3996
|
+
1. Ask for their API URL (default: \`https://proper-cormorant-28.eu-west-1.convex.site\` — but confirm with the user)
|
|
3997
|
+
2. Ask them to generate an API key from their LifeOS settings page
|
|
3998
|
+
3. Run \`lifeos config set-url <url>\` and \`lifeos config set-key <key>\`
|
|
3999
|
+
4. Verify with \`lifeos whoami\`
|
|
4000
|
+
|
|
4001
|
+
## Step 3: Learn about the user
|
|
4002
|
+
|
|
4003
|
+
Have a friendly conversation to understand:
|
|
4004
|
+
|
|
4005
|
+
1. **What's your main focus right now?** (work project, health, learning, side project, etc.)
|
|
4006
|
+
2. **What does a typical day look like?** (wake time, work hours, exercise, breaks)
|
|
4007
|
+
3. **What are your top 2-3 goals for this quarter?** (be specific — "launch MVP by April" not "be productive")
|
|
4008
|
+
4. **How do you like to reflect?** (morning journaling, evening review, weekly planning sessions)
|
|
4009
|
+
5. **Any habits you're building or breaking?**
|
|
4010
|
+
|
|
4011
|
+
Keep it conversational and warm. Don't ask all questions at once — let it flow naturally.
|
|
4012
|
+
|
|
4013
|
+
## Step 4: Create the initial structure
|
|
4014
|
+
|
|
4015
|
+
Based on what you learned, use the CLI to set up:
|
|
4016
|
+
|
|
4017
|
+
### Goals
|
|
4018
|
+
Create 2-3 goals with target dates:
|
|
4019
|
+
\`\`\`
|
|
4020
|
+
lifeos goal create "Goal title" --target-date YYYY-MM-DD --quarter YYYY-QN
|
|
4021
|
+
\`\`\`
|
|
4022
|
+
|
|
4023
|
+
### Initial tasks
|
|
4024
|
+
Create 3-5 starter tasks linked to the goals:
|
|
4025
|
+
\`\`\`
|
|
4026
|
+
lifeos task create "Task title" --due YYYY-MM-DD --goal <goalId>
|
|
4027
|
+
\`\`\`
|
|
4028
|
+
|
|
4029
|
+
### Today's plan
|
|
4030
|
+
Set up today's plan with their wake time and priorities:
|
|
4031
|
+
\`\`\`
|
|
4032
|
+
lifeos plan set YYYY-MM-DD --wake HH:MM --mit <taskId> --p1 <taskId> --p2 <taskId>
|
|
4033
|
+
\`\`\`
|
|
4034
|
+
|
|
4035
|
+
### First journal entry
|
|
4036
|
+
Write a journal entry to kick things off:
|
|
4037
|
+
\`\`\`
|
|
4038
|
+
lifeos journal write --mit "Their MIT for today" --notes "First day using LifeOS. Goals: ..."
|
|
4039
|
+
\`\`\`
|
|
4040
|
+
|
|
4041
|
+
### First win
|
|
4042
|
+
Log a win — setting up LifeOS counts:
|
|
4043
|
+
\`\`\`
|
|
4044
|
+
lifeos win "Set up LifeOS and defined my quarterly goals"
|
|
4045
|
+
\`\`\`
|
|
4046
|
+
|
|
4047
|
+
## Step 5: Suggest routines
|
|
4048
|
+
|
|
4049
|
+
Based on their preferences, suggest daily routines they can do with you:
|
|
4050
|
+
|
|
4051
|
+
- **Morning briefing**: "Each morning, ask me for your morning briefing. I'll run \`lifeos trigger morning-briefing\` and summarize your day."
|
|
4052
|
+
- **Evening journal**: "Before bed, tell me about your day. I'll write your journal entry and log your wins."
|
|
4053
|
+
- **Weekly review**: "Every Sunday, we can do a weekly review together. I'll pull your stats and help you plan the next week."
|
|
4054
|
+
- **Quick capture**: "Anytime you have an idea or thought, just tell me. I'll capture it instantly."
|
|
4055
|
+
|
|
4056
|
+
Let the user know they can say any of these naturally — you'll handle the CLI commands behind the scenes.
|
|
4057
|
+
|
|
4058
|
+
## Step 6: Wrap up
|
|
4059
|
+
|
|
4060
|
+
Summarize what was set up:
|
|
4061
|
+
- Goals created
|
|
4062
|
+
- Tasks queued
|
|
4063
|
+
- Today's plan set
|
|
4064
|
+
- First journal written
|
|
4065
|
+
|
|
4066
|
+
End with something warm like: "You're all set. Your LifeOS is ready. Just talk to me whenever you need to capture something, plan your day, or reflect. I've got your back."
|
|
4067
|
+
` } };
|
|
4068
|
+
return globalThis.__EMBEDDED_SKILLS__ ?? {};
|
|
4069
|
+
}
|
|
4070
|
+
function registerSkillsCommands(program2) {
|
|
4071
|
+
const skills = program2.command("skills").description("Manage LifeOS coding-agent skills");
|
|
4072
|
+
skills.command("install").description("Install LifeOS skills for a supported coding agent").option("--agent <agent>", "Target agent: claude or codex", "claude").option("--json", "JSON output").action(installSkills);
|
|
4073
|
+
}
|
|
4074
|
+
async function installSkills(options) {
|
|
4075
|
+
const json = !!options.json;
|
|
4076
|
+
const agent = parseAgent(options.agent);
|
|
4077
|
+
const skills = getEmbeddedSkills();
|
|
4078
|
+
const skillNames = Object.keys(skills);
|
|
4079
|
+
if (skillNames.length === 0) {
|
|
4080
|
+
if (json) {
|
|
4081
|
+
console.log(JSON.stringify({ error: "No skills bundled" }));
|
|
4082
|
+
} else {
|
|
4083
|
+
console.error(source_default.red("No skills bundled in this build."));
|
|
4084
|
+
}
|
|
4085
|
+
process.exitCode = 1;
|
|
4086
|
+
return;
|
|
4087
|
+
}
|
|
4088
|
+
const baseDir = getAgentBaseDir(agent);
|
|
4089
|
+
const installed = [];
|
|
4090
|
+
const agentName = agent === "claude" ? "Claude Code" : "Codex";
|
|
4091
|
+
for (const [skillName, files] of Object.entries(skills)) {
|
|
4092
|
+
const skillDir = join2(baseDir, skillName);
|
|
4093
|
+
const writtenFiles = [];
|
|
4094
|
+
for (const [relativePath, content] of Object.entries(files)) {
|
|
4095
|
+
const fullPath = join2(skillDir, relativePath);
|
|
4096
|
+
await mkdir(dirname(fullPath), { recursive: true });
|
|
4097
|
+
await writeFile(fullPath, content, "utf-8");
|
|
4098
|
+
writtenFiles.push(relativePath);
|
|
4099
|
+
}
|
|
4100
|
+
installed.push({ name: skillName, files: writtenFiles });
|
|
4101
|
+
}
|
|
4102
|
+
if (json) {
|
|
4103
|
+
console.log(JSON.stringify({ agent, installed, path: baseDir }));
|
|
4104
|
+
} else {
|
|
4105
|
+
for (const skill of installed) {
|
|
4106
|
+
console.log(` ${source_default.green("+")} ${skill.name} ${source_default.dim(`(${skill.files.length} files)`)}`);
|
|
4107
|
+
}
|
|
4108
|
+
console.log();
|
|
4109
|
+
console.log(source_default.green(`Installed ${installed.length} skills to ${baseDir} for ${agentName}`));
|
|
4110
|
+
console.log();
|
|
4111
|
+
console.log(source_default.dim("Run /lifeos-init in your agent to get started."));
|
|
4112
|
+
}
|
|
4113
|
+
}
|
|
4114
|
+
function parseAgent(agent) {
|
|
4115
|
+
if (!agent || agent === "claude")
|
|
4116
|
+
return "claude";
|
|
4117
|
+
if (agent === "codex")
|
|
4118
|
+
return "codex";
|
|
4119
|
+
console.error(source_default.red(`Unsupported agent '${agent}'. Expected 'claude' or 'codex'.`));
|
|
4120
|
+
process.exitCode = 1;
|
|
4121
|
+
return "claude";
|
|
4122
|
+
}
|
|
4123
|
+
|
|
3934
4124
|
// src/index.ts
|
|
3935
4125
|
var program2 = new Command;
|
|
3936
4126
|
program2.name("lifeos").description("Personal Life Operating System").version("0.1.0").option("--json", "Output results as JSON");
|
|
@@ -3969,4 +4159,5 @@ program2.addCommand(searchCommand);
|
|
|
3969
4159
|
program2.addCommand(undoCommand);
|
|
3970
4160
|
program2.addCommand(triggerCommand);
|
|
3971
4161
|
program2.addCommand(dashboardCommand);
|
|
4162
|
+
registerSkillsCommands(program2);
|
|
3972
4163
|
program2.parseAsync(process.argv);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lifeos-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "LifeOS CLI — manage your life operating system from the terminal",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -10,19 +10,23 @@
|
|
|
10
10
|
"productivity",
|
|
11
11
|
"tasks",
|
|
12
12
|
"goals",
|
|
13
|
-
"journal"
|
|
13
|
+
"journal",
|
|
14
|
+
"ai",
|
|
15
|
+
"skills"
|
|
14
16
|
],
|
|
15
17
|
"bin": {
|
|
16
18
|
"lifeos": "./dist/lifeos.mjs"
|
|
17
19
|
},
|
|
18
20
|
"files": [
|
|
19
|
-
"dist/lifeos.mjs"
|
|
21
|
+
"dist/lifeos.mjs",
|
|
22
|
+
"scripts/postinstall.mjs"
|
|
20
23
|
],
|
|
21
24
|
"scripts": {
|
|
22
25
|
"build": "bun run scripts/build.ts",
|
|
23
26
|
"dev": "bun run src/index.ts",
|
|
24
27
|
"check": "tsc --noEmit",
|
|
25
|
-
"start": "node dist/lifeos.mjs"
|
|
28
|
+
"start": "node dist/lifeos.mjs",
|
|
29
|
+
"postinstall": "node scripts/postinstall.mjs"
|
|
26
30
|
},
|
|
27
31
|
"dependencies": {
|
|
28
32
|
"commander": "^13.0.0",
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { join, dirname } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { spawnSync } from "node:child_process";
|
|
6
|
+
import { createInterface } from "node:readline/promises";
|
|
7
|
+
|
|
8
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
const cliEntrypoint = join(__dirname, "..", "dist", "lifeos.mjs");
|
|
10
|
+
|
|
11
|
+
function printBanner() {
|
|
12
|
+
process.stdout.write("\x1b[1;37m");
|
|
13
|
+
process.stdout.write(`
|
|
14
|
+
██╗ ██╗███████╗███████╗ ██████╗ ███████╗
|
|
15
|
+
██║ ██║██╔════╝██╔════╝██╔═══██╗██╔════╝
|
|
16
|
+
██║ ██║█████╗ █████╗ ██║ ██║███████╗
|
|
17
|
+
██║ ██║██╔══╝ ██╔══╝ ██║ ██║╚════██║
|
|
18
|
+
███████╗██║██║ ███████╗╚██████╔╝███████║
|
|
19
|
+
╚══════╝╚═╝╚═╝ ╚══════╝ ╚═════╝ ╚══════╝
|
|
20
|
+
|
|
21
|
+
`);
|
|
22
|
+
process.stdout.write("\x1b[0m");
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function isInteractiveGlobalInstall() {
|
|
26
|
+
return (
|
|
27
|
+
process.env.npm_config_global === "true" &&
|
|
28
|
+
process.stdin.isTTY &&
|
|
29
|
+
process.stdout.isTTY &&
|
|
30
|
+
!process.env.CI
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function hasSkills(agent) {
|
|
35
|
+
const base = join(
|
|
36
|
+
homedir(),
|
|
37
|
+
agent === "claude" ? ".claude" : ".codex",
|
|
38
|
+
"skills",
|
|
39
|
+
);
|
|
40
|
+
return existsSync(join(base, "lifeos-init"));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function installSkills(agent) {
|
|
44
|
+
const result = spawnSync(
|
|
45
|
+
process.execPath,
|
|
46
|
+
[cliEntrypoint, "skills", "install", "--agent", agent],
|
|
47
|
+
{ stdio: "inherit" },
|
|
48
|
+
);
|
|
49
|
+
if (result.status !== 0) {
|
|
50
|
+
throw new Error(`Skill installation failed for agent '${agent}'.`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async function promptForSkills() {
|
|
55
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
56
|
+
try {
|
|
57
|
+
const answer = await rl.question(
|
|
58
|
+
"Install LifeOS skills for your coding agent? (Y/n) ",
|
|
59
|
+
);
|
|
60
|
+
const normalized = answer.trim().toLowerCase();
|
|
61
|
+
if (normalized && normalized !== "y" && normalized !== "yes") return null;
|
|
62
|
+
|
|
63
|
+
process.stdout.write("\n");
|
|
64
|
+
process.stdout.write("Choose your coding agent:\n");
|
|
65
|
+
process.stdout.write(" 1) Claude Code\n");
|
|
66
|
+
process.stdout.write(" 2) Codex\n");
|
|
67
|
+
process.stdout.write(" 3) Skip\n");
|
|
68
|
+
const agentAnswer = await rl.question("Selection [1-3, default 1]: ");
|
|
69
|
+
|
|
70
|
+
switch (agentAnswer.trim()) {
|
|
71
|
+
case "":
|
|
72
|
+
case "1":
|
|
73
|
+
return "claude";
|
|
74
|
+
case "2":
|
|
75
|
+
return "codex";
|
|
76
|
+
case "3":
|
|
77
|
+
return null;
|
|
78
|
+
default:
|
|
79
|
+
process.stdout.write("Unrecognized selection, skipping.\n");
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
} finally {
|
|
83
|
+
rl.close();
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async function main() {
|
|
88
|
+
if (!isInteractiveGlobalInstall()) return;
|
|
89
|
+
|
|
90
|
+
try {
|
|
91
|
+
printBanner();
|
|
92
|
+
|
|
93
|
+
// Auto-update if skills already installed
|
|
94
|
+
if (hasSkills("claude")) {
|
|
95
|
+
installSkills("claude");
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
if (hasSkills("codex")) {
|
|
99
|
+
installSkills("codex");
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// First install — ask the user
|
|
104
|
+
const agent = await promptForSkills();
|
|
105
|
+
if (agent) {
|
|
106
|
+
process.stdout.write("\n");
|
|
107
|
+
installSkills(agent);
|
|
108
|
+
}
|
|
109
|
+
} catch (error) {
|
|
110
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
111
|
+
process.stderr.write(`\nSkill installation skipped: ${message}\n`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
await main();
|