@walruswebdev/daily-devhabit-cli 1.0.6 β 1.1.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 +186 -30
- package/dist/index.js +77 -18
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,79 +1,235 @@
|
|
|
1
|
-
# Daily Dev Habit CLI π
|
|
1
|
+
# Daily Dev Habit CLI (`ddh`) π
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
### *Your engineering history β searchable, structured, synced.*
|
|
4
4
|
|
|
5
|
-
The **Daily Dev Habit CLI**
|
|
5
|
+
The **Daily Dev Habit CLI** is a frictionless command-line tool that helps developers quickly capture:
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
* what they worked on
|
|
8
|
+
* key decisions made
|
|
9
|
+
* blockers and friction
|
|
10
|
+
* progress and scope
|
|
11
|
+
* useful tags for later search
|
|
12
|
+
|
|
13
|
+
All **without leaving the terminal**.
|
|
14
|
+
|
|
15
|
+
Use it to build a lightweight engineering journal, generate weekly status reports, or maintain a decision log across projects β with **cloud sync and offline support**.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## β¨ Why Daily Dev Habit exists
|
|
20
|
+
|
|
21
|
+
Developers face real problems:
|
|
22
|
+
|
|
23
|
+
* You forget what you worked on two days ago
|
|
24
|
+
* Status reports take longer than they should
|
|
25
|
+
* Decisions arenβt documented and must be re-explained
|
|
26
|
+
* Context switching destroys memory
|
|
27
|
+
* Performance reviews rely on βremembering everything you didβ
|
|
28
|
+
|
|
29
|
+
**Daily Dev Habit solves this by making logging effortless.**
|
|
30
|
+
|
|
31
|
+
It prompts you from the terminal and records your work in structured form β to the cloud or locally β so your engineering history is **searchable, exportable, and actually usable**.
|
|
8
32
|
|
|
9
|
-
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## β Key Features
|
|
36
|
+
|
|
37
|
+
* π§ **Structured engineering journal** right in your terminal
|
|
38
|
+
* βοΈ **Cloud sync** (with secure auth token)
|
|
39
|
+
* βοΈ **Offline-first**: falls back to Markdown logs automatically
|
|
40
|
+
* π· **Tagging support** for fast categorization
|
|
41
|
+
* π **Markdown export** for reporting & backups
|
|
42
|
+
* π **WordPress plugin integration available**
|
|
43
|
+
* π Minimal setup β works across platforms
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## π¦ Installation
|
|
10
48
|
|
|
11
49
|
```bash
|
|
12
50
|
npm install -g @walruswebdev/daily-devhabit-cli
|
|
13
51
|
```
|
|
14
52
|
|
|
53
|
+
Verify install:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
ddh --version
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
15
61
|
## β‘ Quick Start
|
|
16
|
-
|
|
62
|
+
|
|
63
|
+
Register:
|
|
17
64
|
|
|
18
65
|
```bash
|
|
19
66
|
ddh register
|
|
20
67
|
```
|
|
21
68
|
|
|
22
|
-
Log in
|
|
69
|
+
Log in:
|
|
70
|
+
|
|
23
71
|
```bash
|
|
24
72
|
ddh login
|
|
25
73
|
```
|
|
26
74
|
|
|
27
|
-
Create your first log
|
|
75
|
+
Create your first log:
|
|
28
76
|
|
|
29
77
|
```bash
|
|
30
78
|
ddh log
|
|
31
79
|
```
|
|
32
80
|
|
|
33
|
-
|
|
81
|
+
Alias for speed:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
ddh l
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
34
88
|
|
|
35
89
|
## π Commands
|
|
36
|
-
`ddh log` (alias: `l`)
|
|
37
|
-
The core command. Launches an interactive survey to capture your current work state.
|
|
38
90
|
|
|
39
|
-
|
|
91
|
+
### `ddh log` (alias: `l`)
|
|
92
|
+
|
|
93
|
+
Launches an interactive survey to capture your current work snapshot:
|
|
40
94
|
|
|
41
|
-
|
|
95
|
+
* **Scope** β API, DB, Feature, Refactor, etc.
|
|
96
|
+
* **Summary** β What did you do?
|
|
97
|
+
* **Key Decisions** β what you chose & why
|
|
98
|
+
* **Friction** β blockers / pain points
|
|
99
|
+
* **Tags** β comma-separated keywords
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
### `ddh export`
|
|
104
|
+
|
|
105
|
+
> New in **v1.1.0**
|
|
106
|
+
|
|
107
|
+
Exports your entire engineering history as Markdown.
|
|
108
|
+
|
|
109
|
+
* Fetches your logs from the cloud
|
|
110
|
+
* Generates a timestamped file like:
|
|
111
|
+
|
|
112
|
+
```
|
|
113
|
+
ddh_export_2025-12-26_20-45.md
|
|
114
|
+
```
|
|
42
115
|
|
|
43
|
-
|
|
116
|
+
* Great for:
|
|
44
117
|
|
|
45
|
-
|
|
118
|
+
* weekly reports
|
|
119
|
+
* retrospectives
|
|
120
|
+
* performance reviews
|
|
121
|
+
* backups
|
|
46
122
|
|
|
47
|
-
|
|
123
|
+
---
|
|
48
124
|
|
|
49
125
|
### `ddh token`
|
|
50
|
-
Displays your current Cloud API Token.
|
|
51
126
|
|
|
52
|
-
|
|
127
|
+
Displays your current **Cloud API token**.
|
|
128
|
+
|
|
129
|
+
Used to connect integrations such as the WordPress plugin.
|
|
130
|
+
|
|
131
|
+
---
|
|
53
132
|
|
|
54
133
|
### `ddh login`
|
|
55
|
-
|
|
134
|
+
|
|
135
|
+
Authenticates and stores your credentials securely on your machine.
|
|
136
|
+
|
|
137
|
+
---
|
|
56
138
|
|
|
57
139
|
### `ddh register`
|
|
58
|
-
Creates a new user account on the Daily Dev Habit platform.
|
|
59
140
|
|
|
60
|
-
|
|
61
|
-
|
|
141
|
+
Creates a new Daily Dev Habit cloud account.
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## π WordPress Integration (Optional)
|
|
146
|
+
|
|
147
|
+
The CLI integrates with the [Daily Dev Habit WordPress Plugin](https://dailydevhabit.com/download/).
|
|
148
|
+
|
|
149
|
+
1. Run:
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
ddh token
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
2. Copy your API token
|
|
156
|
+
3. Paste it inside:
|
|
157
|
+
|
|
158
|
+
> WordPress Admin β Daily Dev Habit β Settings
|
|
159
|
+
|
|
160
|
+
Your WordPress site can now send engineering metrics from an Admin Dashboard form.
|
|
161
|
+
This is helpful for less technical users and/or capturing different aspects of the project development.
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## π‘ Offline Support
|
|
166
|
+
|
|
167
|
+
No internet? No problem.
|
|
62
168
|
|
|
63
|
-
|
|
169
|
+
* CLI detects connectivity loss automatically
|
|
170
|
+
* Switches to **Local Mode**
|
|
171
|
+
* Writes entries to:
|
|
64
172
|
|
|
65
|
-
|
|
173
|
+
```
|
|
174
|
+
OFFLINE_LOGS.md
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
* Stored in the **current working directory**
|
|
178
|
+
* Uses clean Markdown formatting
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## π Tech Stack (for contributors and curious devs)
|
|
184
|
+
|
|
185
|
+
* **Commander** β command routing & argument parsing
|
|
186
|
+
* **Inquirer** β interactive CLI questions
|
|
187
|
+
* **Axios** β HTTP networking to backend API
|
|
188
|
+
* **Conf** β secure local token storage
|
|
189
|
+
* **Path** β cross-platform path reliability
|
|
190
|
+
* **fs** β file system writing for offline/export support
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## π― Who this tool is great for
|
|
66
195
|
|
|
67
|
-
|
|
196
|
+
* solo developers and indie hackers
|
|
197
|
+
* engineers who context-switch frequently
|
|
198
|
+
* freelancers writing client status reports
|
|
199
|
+
* teams wanting light-weight telemetry
|
|
200
|
+
* devs building a **βbrag documentβ**
|
|
201
|
+
* people who hate filling out retro forms Friday afternoon
|
|
68
202
|
|
|
69
|
-
|
|
203
|
+
---
|
|
70
204
|
|
|
71
|
-
##
|
|
72
|
-
Bad internet? No problem. If the CLI cannot connect to the server (or if you are not logged in), it automatically falls back to Local Mode.
|
|
205
|
+
## π§ Roadmap
|
|
73
206
|
|
|
74
|
-
|
|
207
|
+
Planned features:
|
|
75
208
|
|
|
76
|
-
|
|
209
|
+
* π search logs from the CLI
|
|
210
|
+
* π metrics dashboards
|
|
211
|
+
* π€ team workspaces
|
|
212
|
+
* π§© plugin integration ecosystem
|
|
213
|
+
* β± daily reminder option
|
|
214
|
+
|
|
215
|
+
Contributions & ideas welcome!
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## π€ Contributing
|
|
220
|
+
|
|
221
|
+
Pull requests are very welcome β especially since this is an early project.
|
|
222
|
+
|
|
223
|
+
Good first contributions:
|
|
224
|
+
|
|
225
|
+
* docs improvements
|
|
226
|
+
* CLI UX polish
|
|
227
|
+
* validation of prompts
|
|
228
|
+
* bug reports
|
|
229
|
+
* ideas & feature proposals
|
|
230
|
+
|
|
231
|
+
---
|
|
77
232
|
|
|
78
233
|
## π License
|
|
234
|
+
|
|
79
235
|
ISC Β© Lauren Bridges
|
package/dist/index.js
CHANGED
|
@@ -10,14 +10,14 @@ const axios_1 = __importDefault(require("axios"));
|
|
|
10
10
|
const conf_1 = __importDefault(require("conf"));
|
|
11
11
|
const path_1 = __importDefault(require("path"));
|
|
12
12
|
const fs_1 = __importDefault(require("fs"));
|
|
13
|
-
// 1. Initialize Configuration Store
|
|
13
|
+
// 1. Initialize Configuration Store
|
|
14
14
|
const config = new conf_1.default({ projectName: 'daily-devhabit-cli' });
|
|
15
15
|
const program = new commander_1.Command();
|
|
16
16
|
// 2. DEFINE THE CONNECTION
|
|
17
17
|
const DEFAULT_API_URL = 'https://ddh-core-production.up.railway.app';
|
|
18
18
|
const API_URL = process.env.API_URL || DEFAULT_API_URL;
|
|
19
19
|
program
|
|
20
|
-
.version('1.1.
|
|
20
|
+
.version('1.1.1')
|
|
21
21
|
.description('Daily Dev Habit: Engineering Intelligence CLI');
|
|
22
22
|
// --- COMMAND: LOGIN ---
|
|
23
23
|
program
|
|
@@ -32,7 +32,7 @@ program
|
|
|
32
32
|
try {
|
|
33
33
|
const response = await axios_1.default.post(`${API_URL}/auth/login`, credentials);
|
|
34
34
|
const token = response.data.token;
|
|
35
|
-
// Save Token
|
|
35
|
+
// Save Token
|
|
36
36
|
config.set('auth.token', token);
|
|
37
37
|
config.set('auth.email', credentials.email);
|
|
38
38
|
console.log('β
Login Successful! Token saved locally.');
|
|
@@ -59,19 +59,16 @@ program
|
|
|
59
59
|
console.error('β Registration Failed:', error.response?.data?.message || error.message);
|
|
60
60
|
}
|
|
61
61
|
});
|
|
62
|
-
// --- COMMAND: LOG
|
|
62
|
+
// --- COMMAND: LOG ---
|
|
63
63
|
program
|
|
64
64
|
.command('log')
|
|
65
65
|
.alias('l')
|
|
66
66
|
.description('Create a new engineering log entry')
|
|
67
67
|
.action(async () => {
|
|
68
|
-
// 1. Get Token from Config (or Env as backup)
|
|
69
68
|
const token = config.get('auth.token') || process.env.DEV_CLI_TOKEN;
|
|
70
69
|
if (!token) {
|
|
71
70
|
console.log('β You are not logged in. Please run: ddh login');
|
|
72
|
-
// We don't return here because you might want to log offline even if logged out
|
|
73
71
|
}
|
|
74
|
-
// 2. Interactive Prompt
|
|
75
72
|
const answers = await inquirer_1.default.prompt([
|
|
76
73
|
{
|
|
77
74
|
type: 'list',
|
|
@@ -113,23 +110,20 @@ program
|
|
|
113
110
|
origin: 'cli'
|
|
114
111
|
};
|
|
115
112
|
try {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
throw new Error('No token available (Login required for Cloud Sync).');
|
|
119
|
-
}
|
|
113
|
+
if (!token)
|
|
114
|
+
throw new Error('No token available.');
|
|
120
115
|
const response = await axios_1.default.post(`${API_URL}/entries`, payload, {
|
|
121
116
|
headers: { Authorization: `Bearer ${token}` }
|
|
122
117
|
});
|
|
123
118
|
console.log(`\nβ
Log Saved! (ID: ${response.data.id})`);
|
|
124
|
-
console.log(` Stored in: Cloud Database
|
|
119
|
+
console.log(` Stored in: Cloud Database`);
|
|
125
120
|
}
|
|
126
121
|
catch (error) {
|
|
127
|
-
//
|
|
122
|
+
// OFFLINE FALLBACK
|
|
128
123
|
const isOffline = error.code === 'ECONNREFUSED' || error.code === 'ENOTFOUND';
|
|
129
124
|
const isAuthError = !token || (error.response && error.response.status === 401);
|
|
130
125
|
if (isOffline || isAuthError) {
|
|
131
126
|
console.log('\nβ οΈ Could not sync to Cloud. Switching to Local Backup...');
|
|
132
|
-
// Format for Markdown
|
|
133
127
|
const timestamp = new Date().toISOString();
|
|
134
128
|
const backupEntry = `
|
|
135
129
|
## [OFFLINE] ${timestamp}
|
|
@@ -141,8 +135,6 @@ program
|
|
|
141
135
|
- **Tags:** ${payload.tags.join(', ')}
|
|
142
136
|
---
|
|
143
137
|
`;
|
|
144
|
-
// Append to OFFLINE_LOGS.md in project root
|
|
145
|
-
// We use process.cwd() to find the user's current project folder, not the CLI's folder
|
|
146
138
|
const backupPath = path_1.default.join(process.cwd(), 'OFFLINE_LOGS.md');
|
|
147
139
|
fs_1.default.appendFileSync(backupPath, backupEntry);
|
|
148
140
|
console.log(`β
Log saved locally to: ${backupPath}`);
|
|
@@ -152,12 +144,11 @@ program
|
|
|
152
144
|
console.log('π Reason: Server is unreachable.');
|
|
153
145
|
}
|
|
154
146
|
else {
|
|
155
|
-
// Real Error (e.g. 500 Server Error)
|
|
156
147
|
console.error('β Error:', error.response?.data?.message || error.message);
|
|
157
148
|
}
|
|
158
149
|
}
|
|
159
150
|
});
|
|
160
|
-
// --- COMMAND: TOKEN
|
|
151
|
+
// --- COMMAND: TOKEN ---
|
|
161
152
|
program
|
|
162
153
|
.command('token')
|
|
163
154
|
.description('Show your current API token')
|
|
@@ -175,4 +166,72 @@ program
|
|
|
175
166
|
console.log('Run "ddh login" first to generate a token.');
|
|
176
167
|
}
|
|
177
168
|
});
|
|
169
|
+
// --- COMMAND: EXPORT ---
|
|
170
|
+
program
|
|
171
|
+
.command('export')
|
|
172
|
+
.description('Download all cloud logs to a timestamped Markdown file')
|
|
173
|
+
.action(async () => {
|
|
174
|
+
// 1. Get Token
|
|
175
|
+
const token = config.get('auth.token') || process.env.DEV_CLI_TOKEN;
|
|
176
|
+
if (!token) {
|
|
177
|
+
console.error('β Authentication required. Please run "ddh login" first.');
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
try {
|
|
181
|
+
console.log('β³ Fetching logs from Daily Dev Habit Cloud...');
|
|
182
|
+
const response = await axios_1.default.get(`${API_URL}/entries`, {
|
|
183
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
184
|
+
});
|
|
185
|
+
const rows = response.data;
|
|
186
|
+
if (!rows || rows.length === 0) {
|
|
187
|
+
console.log('β οΈ No logs found to export.');
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
// 2. Generate Timestamped Filename
|
|
191
|
+
const now = new Date();
|
|
192
|
+
// Format: YYYY-MM-DD_HH-mm-ss
|
|
193
|
+
const timeString = now.toISOString().replace(/T/, '_').replace(/\..+/, '').replace(/:/g, '-');
|
|
194
|
+
const filename = `ddh_export_${timeString}.md`;
|
|
195
|
+
// 3. Format Markdown
|
|
196
|
+
let markdownContent = '# Daily Dev Habit Export\n\n';
|
|
197
|
+
markdownContent += `> Exported on ${now.toLocaleString()}\n\n`;
|
|
198
|
+
rows.forEach((row) => {
|
|
199
|
+
const date = new Date(row.created_at).toISOString().split('T')[0];
|
|
200
|
+
const scopeBadge = row.scope ? `**[${row.scope.toUpperCase()}]**` : '';
|
|
201
|
+
markdownContent += `## ${date} ${scopeBadge}\n`;
|
|
202
|
+
if (row.decision || row.rationale) {
|
|
203
|
+
// Engineering Log
|
|
204
|
+
if (row.content)
|
|
205
|
+
markdownContent += `* **Note:** ${row.content}\n`;
|
|
206
|
+
if (row.decision)
|
|
207
|
+
markdownContent += `* **Decision:** ${row.decision}\n`;
|
|
208
|
+
if (row.rationale)
|
|
209
|
+
markdownContent += `* **Rationale:** ${row.rationale}\n`;
|
|
210
|
+
if (row.friction)
|
|
211
|
+
markdownContent += `* **Friction:** β οΈ ${row.friction}\n`;
|
|
212
|
+
if (row.tags && row.tags.length > 0)
|
|
213
|
+
markdownContent += `* *Tags:* \`${row.tags}\`\n`;
|
|
214
|
+
}
|
|
215
|
+
else {
|
|
216
|
+
// Journal/Simple Log
|
|
217
|
+
const text = row.content || row.content_html || 'No content';
|
|
218
|
+
markdownContent += `* ${text}\n`;
|
|
219
|
+
}
|
|
220
|
+
markdownContent += '\n---\n\n';
|
|
221
|
+
});
|
|
222
|
+
// 4. Save File
|
|
223
|
+
const outputPath = path_1.default.join(process.cwd(), filename);
|
|
224
|
+
fs_1.default.writeFileSync(outputPath, markdownContent);
|
|
225
|
+
console.log(`β
Successfully exported ${rows.length} entries.`);
|
|
226
|
+
console.log(`π File saved to: ${outputPath}`);
|
|
227
|
+
}
|
|
228
|
+
catch (error) {
|
|
229
|
+
if (error.response && error.response.status === 401) {
|
|
230
|
+
console.error('β Unauthorized: Token invalid. Try "ddh login" again.');
|
|
231
|
+
}
|
|
232
|
+
else {
|
|
233
|
+
console.error('β Export failed:', error.message);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
});
|
|
178
237
|
program.parse(process.argv);
|