niahere 0.2.35 → 0.2.36

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
@@ -1,11 +1,25 @@
1
1
  # nia
2
2
 
3
- A personal AI assistant that runs as a background daemon. Handles scheduled jobs, terminal chat, Telegram, and Slack powered by Claude.
3
+ A personal AI agent you fork and make your own. Small enough to understand, built for one user. Powered by Claude Agent SDK.
4
4
 
5
5
  - npm package: [`niahere`](https://www.npmjs.com/package/niahere)
6
6
  - CLI command: `nia`
7
7
  - Website: [niahere.com](https://niahere.com)
8
8
 
9
+ ## Philosophy
10
+
11
+ **Small enough to understand.** One process, a few source files. No microservices, no message queues, no abstraction layers. Have Claude Code walk you through it.
12
+
13
+ **Built for one user.** This isn't a framework. It's working software that fits your exact needs. You fork it and have Claude Code make it match your exact needs.
14
+
15
+ **Customization = code changes.** No configuration sprawl. Want different behavior? Modify the code. The codebase is small enough that this is safe.
16
+
17
+ **AI-native.** No installation wizard; Claude Code guides setup. No monitoring dashboard; ask Claude what's happening. No debugging tools; describe the problem, Claude fixes it.
18
+
19
+ **Skills over features.** Contributors shouldn't add features to the codebase. Instead, they contribute claude code skills like `/add-discord` that transform your fork. You end up with clean code that does exactly what you need.
20
+
21
+ **Best harness, best model.** This runs on Claude Agent SDK, which means you're running Claude Code directly. The harness matters. A bad harness makes even smart models seem dumb, a good harness gives them superpowers.
22
+
9
23
  ## Quick Start
10
24
 
11
25
  ```bash
@@ -14,6 +28,18 @@ nia init # guided setup (database, channels, persona, visual iden
14
28
  nia start # starts daemon + registers OS service
15
29
  ```
16
30
 
31
+ ## What It Supports
32
+
33
+ - **Telegram** — message your agent from your phone, typing indicator while processing
34
+ - **Slack** — Socket Mode bot with thread awareness, thinking emoji, watch channels for proactive monitoring
35
+ - **Terminal chat** — REPL with session resume support
36
+ - **Scheduled jobs** — recurring jobs and crons that run Claude and can message you back
37
+ - **Persona system** — customizable identity, soul, owner profile, and on-demand memory
38
+ - **Skills** — loads skills from multiple directories, invokable as slash commands
39
+ - **Cross-platform service** — launchd (macOS), systemd (Linux), service-aware restart
40
+ - **MCP tools** — 18 tools for job management, messaging, memory, and channel control
41
+ - **Optional integrations** — add Gmail, Discord, and more via skills
42
+
17
43
  ## Commands
18
44
 
19
45
  ```
@@ -50,30 +76,6 @@ nia channels — show channel status (on/off)
50
76
  nia channels on / off — enable/disable channels
51
77
  ```
52
78
 
53
- ## Features
54
-
55
- - **Jobs & crons** — jobs run during active hours, crons run 24/7. Stored in PostgreSQL, auto-reload via LISTEN/NOTIFY. One-shot jobs auto-disable after execution. Full JSONL traces with Codex session IDs.
56
- - **Terminal chat** — REPL with session resume support
57
- - **Telegram** — bot with access control, typing indicator while processing
58
- - **Slack** — Socket Mode bot with thinking emoji reactions, thread awareness (auto-listens to follow-ups without @mention), thread context fetching, owner vs non-owner access control, prompt injection defense
59
- - **Persona system** — customizable identity, soul, owner profile, and on-demand memory
60
- - **Visual identity** — AI-generated profile pictures via Gemini, customizable during `nia init`
61
- - **Cross-platform service** — launchd (macOS), systemd (Linux), service-aware restart
62
- - **Skills** — loads skills from `~/.shared/skills/`, `~/.claude/skills/`, `~/.codex/skills/`, and bundled skills
63
- - **Dev mode** — `nia channels off` disables Telegram/Slack for local development without conflicts
64
-
65
- ## Updating
66
-
67
- ```bash
68
- npm i -g niahere # pulls the latest version from npm
69
- ```
70
-
71
- To publish a new version after making changes:
72
-
73
- ```bash
74
- npm run release # bumps patch version, publishes to npm, pushes git tag
75
- ```
76
-
77
79
  ## Architecture
78
80
 
79
81
  All config and data lives in `~/.niahere/`:
@@ -93,6 +95,14 @@ All config and data lives in `~/.niahere/`:
93
95
  nia.pid, daemon.log, cron-state.json, cron-audit.jsonl
94
96
  ```
95
97
 
98
+ ## Contributing
99
+
100
+ **Don't add features. Add skills.**
101
+
102
+ If you want to add Discord support, don't create a PR that adds Discord alongside Telegram. Instead, contribute a skill folder (`skills/add-discord/SKILL.md`) that teaches Claude Code how to transform a nia installation to use Discord.
103
+
104
+ Users then run `/add-discord` on their fork and get clean code that does exactly what they need, not a bloated system trying to support every use case.
105
+
96
106
  ## Requirements
97
107
 
98
108
  - [Bun](https://bun.sh) runtime (auto-installed if missing)
@@ -101,6 +111,12 @@ All config and data lives in `~/.niahere/`:
101
111
  - Gemini API key (optional, for image generation — `nia config set gemini_api_key ...`)
102
112
  - OpenAI API key (optional, for image generation — `nia config set openai_api_key ...`)
103
113
 
114
+ ## Updating
115
+
116
+ ```bash
117
+ npm i -g niahere # pulls the latest version from npm
118
+ ```
119
+
104
120
  ## Author
105
121
 
106
122
  Aman ([amankumar.ai](https://amankumar.ai))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "niahere",
3
- "version": "0.2.35",
3
+ "version": "0.2.36",
4
4
  "description": "A personal AI assistant daemon — scheduled jobs, chat across Telegram and Slack, persona system, and visual identity.",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -0,0 +1,104 @@
1
+ ---
2
+ name: taskmaster
3
+ description: |
4
+ Completion guard that prevents premature task abandonment. Use when wrapping up
5
+ any non-trivial task, before claiming work is "done", or when you catch yourself
6
+ writing a summary instead of finishing the work. Also use when the user says
7
+ "don't stop early", "finish everything", "make sure it's actually done", or
8
+ "verify completion". Adapted from github.com/blader/taskmaster.
9
+ ---
10
+
11
+ # Taskmaster
12
+
13
+ Completion guard. Progress is not completion. Before you stop, prove the work is done.
14
+
15
+ ## When to Invoke
16
+
17
+ - Before claiming any non-trivial task is complete
18
+ - When you're about to write a summary of what you did
19
+ - When you notice yourself using phrases like "significant progress", "mostly done", or "remaining work would require..."
20
+ - When the user explicitly asks you to finish everything
21
+
22
+ ## The Completion Checklist
23
+
24
+ Run every item. Do not skip any. Do not summarize — execute.
25
+
26
+ ### 1. Goal Confrontation (Do This First)
27
+
28
+ Answer these three questions explicitly in your response:
29
+
30
+ a. **What is the user's stated goal or success criterion?** Write it out verbatim.
31
+ b. **Is it achieved RIGHT NOW?** Answer "yes" or "no". Not "partially", not "mostly", not "significant progress was made". Yes or no.
32
+ c. **If no:** you are NOT DONE. Go do more work.
33
+
34
+ The ONLY exception is if the user explicitly told you to stop or deprioritized the goal. There is no other valid reason to stop.
35
+
36
+ ### 2. Re-read the Original Request
37
+
38
+ Go back to the user's original message(s). List every discrete request or acceptance criterion. For each one, confirm it is **fully addressed** — not started, not in progress, FULLY done.
39
+
40
+ If the user changed their mind or withdrew a request, treat it as resolved.
41
+
42
+ ### 3. Check the Task List
43
+
44
+ Review every task. Any task not marked completed? Do it now — unless the user said to skip it.
45
+
46
+ ### 4. Check the Plan
47
+
48
+ Walk through each step of the plan, INCLUDING verification steps. Any step skipped or partially done? Finish it.
49
+
50
+ If the plan includes verification steps (builds, tests, lints, type-checks, smoke tests), you MUST actually run them and see them pass. Do not skip them or claim they pass without evidence.
51
+
52
+ ### 5. Check for Errors
53
+
54
+ Did anything fail or remain unfinished? Fix it. This applies to ALL types of problems — logic errors, missing functionality, incomplete refactors, broken scripts, configuration issues, or anything else that prevents the work from being fully done.
55
+
56
+ ### 6. Check for Loose Ends
57
+
58
+ - TODO comments you left behind?
59
+ - Placeholder code?
60
+ - Missing tests for new code?
61
+ - Untested changes?
62
+ - Follow-ups you noted but didn't act on?
63
+
64
+ If any exist, resolve them now.
65
+
66
+ ### 7. Check for Blockers
67
+
68
+ If something is blocking you, do NOT give up. Try a different approach, read more code, search for examples, re-examine your assumptions.
69
+
70
+ "I didn't cause this bug" is not an excuse to stop — if it blocks your task, fix it. You own the outcome, not just your diff.
71
+
72
+ ## Anti-Rationalization Guide
73
+
74
+ These are NOT valid reasons to stop:
75
+
76
+ | Rationalization | Reality |
77
+ |---|---|
78
+ | "Diminishing returns" | The goal isn't met. Keep working. |
79
+ | "Significant progress was made" | Progress is not completion. |
80
+ | "Would require broader architectural changes" | Then make them. |
81
+ | "No single dominant hotspot" | Keep looking. |
82
+ | "Tried N approaches" | Try N+1. |
83
+ | "I can't do X" | You haven't tried X yet. |
84
+ | "This is a pre-existing issue" | If it blocks your task, it's your issue. |
85
+ | "The remaining work is complex" | That's not a reason to stop. That's a description of your job. |
86
+
87
+ ## Do Not Narrate — Execute
88
+
89
+ If any incomplete work remains, your ONLY job is to DO that work right now.
90
+
91
+ - Do NOT respond by explaining what the remaining tasks are
92
+ - Do NOT describe their complexity or list their dependencies
93
+ - Do NOT ask for permission to proceed
94
+ - Do NOT write summaries of what is left
95
+
96
+ Open files, write code, run commands, fix bugs. Act.
97
+
98
+ ## User Instructions Override
99
+
100
+ The user's latest instructions always take priority. If the user said to stop, move on, or skip something — respect that. Do not force completion of work the user no longer wants.
101
+
102
+ ## Attribution
103
+
104
+ Core ideas adapted from [Taskmaster](https://github.com/blader/taskmaster) by blader (MIT).
@@ -7,6 +7,7 @@ import { resetConfig } from "../utils/config";
7
7
  import { runMigrations } from "../db/migrate";
8
8
  import { closeDb } from "../db/connection";
9
9
  import { startDaemon, isRunning } from "../core/daemon";
10
+ import { registerService, isServiceInstalled } from "./service";
10
11
  import { errMsg } from "../utils/errors";
11
12
  import { enrichSlackConfig } from "../cli/channels";
12
13
  import yaml from "js-yaml";
@@ -434,12 +435,25 @@ export async function runInit(): Promise<void> {
434
435
 
435
436
  resetConfig();
436
437
 
438
+ // Install system service (launchd/systemd) for auto-restart on crash
439
+ if (!isServiceInstalled()) {
440
+ try {
441
+ await registerService();
442
+ console.log(`\n \u2713 installed system service (auto-restart on crash)`);
443
+ } catch (err) {
444
+ console.log(`\n \u26a0 could not install system service: ${errMsg(err)}`);
445
+ console.log(` run 'nia service install' manually for auto-restart`);
446
+ }
447
+ } else {
448
+ console.log(`\n - system service already installed`);
449
+ }
450
+
437
451
  // Auto-start daemon
438
452
  if (!isRunning()) {
439
453
  const pid = startDaemon();
440
- console.log(`\n \u2713 nia started (pid: ${pid})`);
454
+ console.log(` \u2713 nia started (pid: ${pid})`);
441
455
  } else {
442
- console.log(`\n - nia already running`);
456
+ console.log(` - nia already running`);
443
457
  }
444
458
 
445
459
  console.log("\nDone.");
@@ -8,7 +8,15 @@ const PLIST_NAME = "com.niahere.agent";
8
8
  const SYSTEMD_UNIT = "niahere.service";
9
9
 
10
10
  function getExecCommand(): [string, string] {
11
- return [process.execPath, process.argv[1]];
11
+ const execPath = process.execPath;
12
+ // process.argv[1] may be undefined when called outside the normal CLI flow
13
+ // (e.g. from bun -e or programmatic import). Fall back to the known entry point.
14
+ let cliPath = process.argv[1];
15
+ if (!cliPath || cliPath === "undefined") {
16
+ const { resolve } = require("path");
17
+ cliPath = resolve(import.meta.dir, "../cli/index.ts");
18
+ }
19
+ return [execPath, cliPath];
12
20
  }
13
21
 
14
22
  // --- macOS launchd ---
@@ -162,6 +162,20 @@ export async function runDaemon(): Promise<void> {
162
162
  }
163
163
  }
164
164
 
165
+ // Crash handlers — ensure PID cleanup and logging on unhandled errors.
166
+ // Without these, an unhandled rejection kills the process silently,
167
+ // leaving a stale PID file that blocks restarts and hides the cause.
168
+ process.on("uncaughtException", (err) => {
169
+ log.fatal({ err }, "uncaught exception — cleaning up");
170
+ removePid();
171
+ process.exit(1);
172
+ });
173
+ process.on("unhandledRejection", (reason) => {
174
+ log.fatal({ reason }, "unhandled rejection — cleaning up");
175
+ removePid();
176
+ process.exit(1);
177
+ });
178
+
165
179
  writePid(process.pid);
166
180
  log.info({ pid: process.pid }, "daemon started");
167
181