clawpilot 0.1.1
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 +67 -0
- package/bin/cli.js +100 -0
- package/docs/PUBLISH_CHECKLIST.md +22 -0
- package/package.json +35 -0
- package/skill/SKILL.md +22 -0
- package/skill/manifest.json +6 -0
- package/src/install.js +181 -0
- package/templates/identity.md +6 -0
- package/templates/soul-injection.md +14 -0
- package/templates/soul.productivity.md +17 -0
package/README.md
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# clawpilot
|
|
2
|
+
|
|
3
|
+
OpenClaw productivity copilot installer and skill package.
|
|
4
|
+
|
|
5
|
+
## What it does
|
|
6
|
+
|
|
7
|
+
`clawpilot` installs a productivity-focused OpenClaw skill with a simple daily loop:
|
|
8
|
+
- Morning planning (top 3 tasks)
|
|
9
|
+
- Midday progress check
|
|
10
|
+
- Evening review and next-step setup
|
|
11
|
+
|
|
12
|
+
The installer also:
|
|
13
|
+
- Copies `skill/` into `~/.openclaw/skills/clawpilot-productivity`
|
|
14
|
+
- Adds or updates `clawpilot-productivity` under `openclaw.json`
|
|
15
|
+
- Injects a productivity section into `workspace/SOUL.md` (idempotent)
|
|
16
|
+
- Writes a default `workspace/IDENTITY.md`
|
|
17
|
+
|
|
18
|
+
## Install
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npx clawpilot@latest
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Or run locally:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install
|
|
28
|
+
npm run test
|
|
29
|
+
node bin/cli.js install
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## CLI options
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
clawpilot install [options]
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Options:
|
|
39
|
+
- `--home <path>`: Override OpenClaw home directory
|
|
40
|
+
- `--force`: Replace existing skill installation
|
|
41
|
+
- `--morning <HH:mm>`: Morning check-in time (default `09:00`)
|
|
42
|
+
- `--midday <HH:mm>`: Midday check-in time (default `14:00`)
|
|
43
|
+
- `--evening <HH:mm>`: Evening check-in time (default `21:30`)
|
|
44
|
+
|
|
45
|
+
## OpenClaw paths
|
|
46
|
+
|
|
47
|
+
By default, the installer writes to:
|
|
48
|
+
- `~/.openclaw/skills/clawpilot-productivity/`
|
|
49
|
+
- `~/.openclaw/openclaw.json`
|
|
50
|
+
- `~/.openclaw/workspace/SOUL.md`
|
|
51
|
+
- `~/.openclaw/workspace/IDENTITY.md`
|
|
52
|
+
|
|
53
|
+
You can override the target path with:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
node bin/cli.js install --home /custom/path
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Development
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
npm test
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Publish
|
|
66
|
+
|
|
67
|
+
See `docs/PUBLISH_CHECKLIST.md`.
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const os = require('node:os');
|
|
4
|
+
const path = require('node:path');
|
|
5
|
+
const { installSkill, DEFAULT_SCHEDULE } = require('../src/install');
|
|
6
|
+
|
|
7
|
+
function printHelp() {
|
|
8
|
+
console.log('clawpilot - OpenClaw productivity copilot');
|
|
9
|
+
console.log('');
|
|
10
|
+
console.log('Usage:');
|
|
11
|
+
console.log(' clawpilot install [options]');
|
|
12
|
+
console.log(' clawpilot --help');
|
|
13
|
+
console.log('');
|
|
14
|
+
console.log('Commands:');
|
|
15
|
+
console.log(' install Install clawpilot-productivity skill into OpenClaw');
|
|
16
|
+
console.log('');
|
|
17
|
+
console.log('Options:');
|
|
18
|
+
console.log(' --home <path> Override OpenClaw home directory');
|
|
19
|
+
console.log(' --force Replace existing clawpilot skill installation');
|
|
20
|
+
console.log(` --morning <HH:mm> Morning check-in time (default: ${DEFAULT_SCHEDULE.morning})`);
|
|
21
|
+
console.log(` --midday <HH:mm> Midday check-in time (default: ${DEFAULT_SCHEDULE.midday})`);
|
|
22
|
+
console.log(` --evening <HH:mm> Evening check-in time (default: ${DEFAULT_SCHEDULE.evening})`);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function parseOptions(args) {
|
|
26
|
+
const options = {
|
|
27
|
+
force: false,
|
|
28
|
+
schedule: {}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
32
|
+
const arg = args[index];
|
|
33
|
+
if (arg === '--force') {
|
|
34
|
+
options.force = true;
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
if (arg === '--home') {
|
|
38
|
+
options.openClawHome = args[index + 1];
|
|
39
|
+
index += 1;
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
if (arg === '--morning') {
|
|
43
|
+
options.schedule.morning = args[index + 1];
|
|
44
|
+
index += 1;
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
if (arg === '--midday') {
|
|
48
|
+
options.schedule.midday = args[index + 1];
|
|
49
|
+
index += 1;
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (arg === '--evening') {
|
|
53
|
+
options.schedule.evening = args[index + 1];
|
|
54
|
+
index += 1;
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
throw new Error(`Unknown option: ${arg}`);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return options;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async function main() {
|
|
64
|
+
const args = process.argv.slice(2);
|
|
65
|
+
const command = args[0] || 'install';
|
|
66
|
+
const commandArgs = args.slice(1);
|
|
67
|
+
|
|
68
|
+
if (command === '--help' || command === '-h' || command === 'help') {
|
|
69
|
+
printHelp();
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (command !== 'install') {
|
|
74
|
+
console.error(`Unknown command: ${command}`);
|
|
75
|
+
console.error('Run "clawpilot --help" for usage.');
|
|
76
|
+
process.exitCode = 1;
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const projectRoot = path.resolve(__dirname, '..');
|
|
81
|
+
const options = parseOptions(commandArgs);
|
|
82
|
+
const openClawHome = options.openClawHome || process.env.OPENCLAW_HOME || path.join(os.homedir(), '.openclaw');
|
|
83
|
+
|
|
84
|
+
const result = await installSkill({
|
|
85
|
+
openClawHome,
|
|
86
|
+
packageRoot: projectRoot,
|
|
87
|
+
schedule: options.schedule,
|
|
88
|
+
force: options.force
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
console.log(`Installed skill at: ${result.skillDir}`);
|
|
92
|
+
console.log(`Updated config at: ${result.configPath}`);
|
|
93
|
+
console.log(`Updated workspace SOUL at: ${result.workspaceSoulPath}`);
|
|
94
|
+
console.log(`Updated workspace identity at: ${result.identityPath}`);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
main().catch((error) => {
|
|
98
|
+
console.error(error.message);
|
|
99
|
+
process.exitCode = 1;
|
|
100
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Publish Checklist
|
|
2
|
+
|
|
3
|
+
Use this checklist before publishing a new `clawpilot` version to npm.
|
|
4
|
+
|
|
5
|
+
1. Verify tests:
|
|
6
|
+
- `npm test`
|
|
7
|
+
2. Verify installer behavior locally:
|
|
8
|
+
- `node bin/cli.js install --home <temp-dir>`
|
|
9
|
+
3. Review package metadata:
|
|
10
|
+
- `name`
|
|
11
|
+
- `version`
|
|
12
|
+
- `bin`
|
|
13
|
+
- `license`
|
|
14
|
+
4. Confirm npm auth:
|
|
15
|
+
- `npm whoami`
|
|
16
|
+
5. Dry-run package contents:
|
|
17
|
+
- `npm pack --dry-run`
|
|
18
|
+
6. Publish:
|
|
19
|
+
- `npm publish --access public`
|
|
20
|
+
7. Validate release:
|
|
21
|
+
- `npm view clawpilot version`
|
|
22
|
+
- `npx clawpilot@latest --help`
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "clawpilot",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "OpenClaw productivity copilot installer and skill package.",
|
|
5
|
+
"private": false,
|
|
6
|
+
"bin": {
|
|
7
|
+
"clawpilot": "bin/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"bin/",
|
|
11
|
+
"src/",
|
|
12
|
+
"skill/",
|
|
13
|
+
"templates/",
|
|
14
|
+
"docs/",
|
|
15
|
+
"README.md"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"test": "node --test"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"openclaw",
|
|
22
|
+
"claw",
|
|
23
|
+
"productivity",
|
|
24
|
+
"copilot"
|
|
25
|
+
],
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "https://github.com/RyanSparkc/clawpilot.git"
|
|
30
|
+
},
|
|
31
|
+
"homepage": "https://github.com/RyanSparkc/clawpilot#readme",
|
|
32
|
+
"engines": {
|
|
33
|
+
"node": ">=18.0.0"
|
|
34
|
+
}
|
|
35
|
+
}
|
package/skill/SKILL.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Clawpilot Productivity Skill
|
|
2
|
+
|
|
3
|
+
You are a productivity copilot focused on helping the user ship meaningful work each day.
|
|
4
|
+
|
|
5
|
+
## Core Loop
|
|
6
|
+
|
|
7
|
+
1. Morning planning:
|
|
8
|
+
- Ask for the user's top 3 outcome-based tasks.
|
|
9
|
+
- Ensure each task is specific and verifiable.
|
|
10
|
+
2. Midday check-in:
|
|
11
|
+
- Ask what is done, blocked, or deferred.
|
|
12
|
+
- Help remove one blocker.
|
|
13
|
+
3. Evening review:
|
|
14
|
+
- Summarize completed work.
|
|
15
|
+
- Capture one improvement for tomorrow.
|
|
16
|
+
|
|
17
|
+
## Tone and Constraints
|
|
18
|
+
|
|
19
|
+
- Keep responses short and action-oriented.
|
|
20
|
+
- Be supportive and direct.
|
|
21
|
+
- Avoid guilt, shame, or perfectionist framing.
|
|
22
|
+
- Prefer one next action when the user is stuck.
|
package/src/install.js
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
const fs = require('node:fs');
|
|
2
|
+
const path = require('node:path');
|
|
3
|
+
|
|
4
|
+
const SKILL_ID = 'clawpilot-productivity';
|
|
5
|
+
const MARKER_START = '<!-- clawpilot:productivity:start -->';
|
|
6
|
+
const MARKER_END = '<!-- clawpilot:productivity:end -->';
|
|
7
|
+
const DEFAULT_SCHEDULE = {
|
|
8
|
+
morning: '09:00',
|
|
9
|
+
midday: '14:00',
|
|
10
|
+
evening: '21:30'
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
function copyDir(source, destination) {
|
|
14
|
+
fs.mkdirSync(destination, { recursive: true });
|
|
15
|
+
const entries = fs.readdirSync(source, { withFileTypes: true });
|
|
16
|
+
for (const entry of entries) {
|
|
17
|
+
const sourcePath = path.join(source, entry.name);
|
|
18
|
+
const destinationPath = path.join(destination, entry.name);
|
|
19
|
+
if (entry.isDirectory()) {
|
|
20
|
+
copyDir(sourcePath, destinationPath);
|
|
21
|
+
} else {
|
|
22
|
+
fs.copyFileSync(sourcePath, destinationPath);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function deepMerge(target, source) {
|
|
28
|
+
const result = { ...target };
|
|
29
|
+
for (const [key, value] of Object.entries(source)) {
|
|
30
|
+
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
|
31
|
+
result[key] = deepMerge(result[key] || {}, value);
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
result[key] = value;
|
|
35
|
+
}
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function readJson(filePath) {
|
|
40
|
+
if (!fs.existsSync(filePath)) {
|
|
41
|
+
return {};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
46
|
+
} catch {
|
|
47
|
+
return {};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function writeJson(filePath, data) {
|
|
52
|
+
fs.writeFileSync(filePath, JSON.stringify(data, null, 2) + '\n', 'utf8');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function upsertInstalledSkill(config) {
|
|
56
|
+
if (!Array.isArray(config.installedSkills)) {
|
|
57
|
+
config.installedSkills = [];
|
|
58
|
+
}
|
|
59
|
+
if (!config.installedSkills.includes(SKILL_ID)) {
|
|
60
|
+
config.installedSkills.push(SKILL_ID);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function normalizeSchedule(schedule) {
|
|
65
|
+
return {
|
|
66
|
+
...DEFAULT_SCHEDULE,
|
|
67
|
+
...(schedule || {})
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function upsertWorkspaceSoul(soulPath, injectionText) {
|
|
72
|
+
const normalizedInjection = `${MARKER_START}\n${injectionText.trim()}\n${MARKER_END}`;
|
|
73
|
+
const existing = fs.existsSync(soulPath)
|
|
74
|
+
? fs.readFileSync(soulPath, 'utf8')
|
|
75
|
+
: '# Agent Soul\n';
|
|
76
|
+
const markerRegex = new RegExp(`${MARKER_START}[\\s\\S]*?${MARKER_END}\\n?`, 'g');
|
|
77
|
+
const cleaned = existing.replace(markerRegex, '').trimEnd();
|
|
78
|
+
const nextContent = `${cleaned}\n\n${normalizedInjection}\n`;
|
|
79
|
+
fs.writeFileSync(soulPath, nextContent, 'utf8');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function ensureSkillManifest(skillDir) {
|
|
83
|
+
const manifestPath = path.join(skillDir, 'manifest.json');
|
|
84
|
+
if (fs.existsSync(manifestPath)) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const manifest = {
|
|
89
|
+
id: SKILL_ID,
|
|
90
|
+
name: 'Clawpilot Productivity',
|
|
91
|
+
version: '0.1.0',
|
|
92
|
+
entry: 'SOUL.md'
|
|
93
|
+
};
|
|
94
|
+
writeJson(manifestPath, manifest);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async function installSkill({
|
|
98
|
+
openClawHome,
|
|
99
|
+
packageRoot,
|
|
100
|
+
schedule,
|
|
101
|
+
force = false,
|
|
102
|
+
timezone = Intl.DateTimeFormat().resolvedOptions().timeZone || 'UTC'
|
|
103
|
+
}) {
|
|
104
|
+
const skillsDir = path.join(openClawHome, 'skills');
|
|
105
|
+
const skillDir = path.join(openClawHome, 'skills', SKILL_ID);
|
|
106
|
+
const workspaceDir = path.join(openClawHome, 'workspace');
|
|
107
|
+
const configPath = path.join(openClawHome, 'openclaw.json');
|
|
108
|
+
const soulPath = path.join(skillDir, 'SOUL.md');
|
|
109
|
+
const workspaceSoulPath = path.join(workspaceDir, 'SOUL.md');
|
|
110
|
+
const identityPath = path.join(workspaceDir, 'IDENTITY.md');
|
|
111
|
+
|
|
112
|
+
const skillSourceDir = path.join(packageRoot, 'skill');
|
|
113
|
+
const templateDir = path.join(packageRoot, 'templates');
|
|
114
|
+
const baseSoulTemplate = fs.readFileSync(path.join(templateDir, 'soul.productivity.md'), 'utf8');
|
|
115
|
+
const injectionTemplate = fs.readFileSync(path.join(templateDir, 'soul-injection.md'), 'utf8');
|
|
116
|
+
const identityTemplate = fs.readFileSync(path.join(templateDir, 'identity.md'), 'utf8');
|
|
117
|
+
|
|
118
|
+
fs.mkdirSync(openClawHome, { recursive: true });
|
|
119
|
+
fs.mkdirSync(skillsDir, { recursive: true });
|
|
120
|
+
fs.mkdirSync(workspaceDir, { recursive: true });
|
|
121
|
+
|
|
122
|
+
if (fs.existsSync(skillDir)) {
|
|
123
|
+
if (!force) {
|
|
124
|
+
throw new Error(`Skill already installed: ${skillDir}. Re-run with force to replace.`);
|
|
125
|
+
}
|
|
126
|
+
fs.rmSync(skillDir, { recursive: true, force: true });
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (fs.existsSync(skillSourceDir)) {
|
|
130
|
+
copyDir(skillSourceDir, skillDir);
|
|
131
|
+
} else {
|
|
132
|
+
fs.mkdirSync(skillDir, { recursive: true });
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
fs.writeFileSync(soulPath, baseSoulTemplate, 'utf8');
|
|
136
|
+
ensureSkillManifest(skillDir);
|
|
137
|
+
upsertWorkspaceSoul(workspaceSoulPath, injectionTemplate);
|
|
138
|
+
fs.writeFileSync(identityPath, identityTemplate, 'utf8');
|
|
139
|
+
|
|
140
|
+
let config = readJson(configPath);
|
|
141
|
+
const existingEntry = (((config.skills || {}).entries || {})[SKILL_ID]) || {};
|
|
142
|
+
const mergedEntry = deepMerge(existingEntry, {
|
|
143
|
+
enabled: true,
|
|
144
|
+
mode: 'productivity',
|
|
145
|
+
timezone,
|
|
146
|
+
schedule: normalizeSchedule(schedule)
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
config = deepMerge(config, {
|
|
150
|
+
skills: {
|
|
151
|
+
entries: {
|
|
152
|
+
[SKILL_ID]: mergedEntry
|
|
153
|
+
},
|
|
154
|
+
load: {
|
|
155
|
+
extraDirs: Array.isArray(config.skills?.load?.extraDirs)
|
|
156
|
+
? config.skills.load.extraDirs
|
|
157
|
+
: []
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
if (!config.skills.load.extraDirs.includes(skillsDir)) {
|
|
163
|
+
config.skills.load.extraDirs.push(skillsDir);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
upsertInstalledSkill(config);
|
|
167
|
+
writeJson(configPath, config);
|
|
168
|
+
|
|
169
|
+
return {
|
|
170
|
+
skillDir,
|
|
171
|
+
configPath,
|
|
172
|
+
workspaceSoulPath,
|
|
173
|
+
identityPath
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
module.exports = {
|
|
178
|
+
installSkill,
|
|
179
|
+
SKILL_ID,
|
|
180
|
+
DEFAULT_SCHEDULE
|
|
181
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
## Clawpilot Productivity Loop
|
|
2
|
+
|
|
3
|
+
Run this daily structure with minimal friction:
|
|
4
|
+
|
|
5
|
+
- Morning: ask for 3 outcome-based tasks and make each one measurable.
|
|
6
|
+
- Midday: collect status (`done`, `blocked`, or `deferred`) and unblock one thing.
|
|
7
|
+
- Evening: summarize wins, note one lesson, and queue tomorrow's first action.
|
|
8
|
+
|
|
9
|
+
Coaching rules:
|
|
10
|
+
|
|
11
|
+
- Keep guidance direct and practical.
|
|
12
|
+
- Use supportive language, never guilt-driven language.
|
|
13
|
+
- If progress is behind, offer one focused 25-minute rescue sprint.
|
|
14
|
+
- Avoid long motivational monologues.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Clawpilot Productivity Copilot
|
|
2
|
+
|
|
3
|
+
You are a friendly productivity partner focused on work execution.
|
|
4
|
+
|
|
5
|
+
Daily flow:
|
|
6
|
+
- Morning: define top 3 outcome-based tasks.
|
|
7
|
+
- Midday: check progress and identify one blocker.
|
|
8
|
+
- Evening: review completion and prepare tomorrow's first task.
|
|
9
|
+
|
|
10
|
+
Tone:
|
|
11
|
+
- Keep responses concise, practical, and supportive.
|
|
12
|
+
- Avoid guilt-driven language.
|
|
13
|
+
- Prioritize momentum over perfection.
|
|
14
|
+
|
|
15
|
+
Recovery mode:
|
|
16
|
+
- If user is behind, suggest one 25-minute rescue sprint.
|
|
17
|
+
- Limit rescue mode to two times per week.
|