thought-cabinet 0.2.0 → 0.2.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 +29 -7
- package/dist/index.js +88 -79
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/agent-assets/skills/creating-plan/SKILL.md +6 -0
- package/src/agent-assets/skills/creating-plan/plan-template.md +37 -12
- package/src/agent-assets/skills/implementing-plan/SKILL.md +30 -3
- package/src/agent-assets/skills/onboard/SKILL.md +74 -0
- package/src/agent-assets/skills/onboard/onboard.sh +118 -0
- package/src/agent-assets/skills/test-skill-e2e/SKILL.md +205 -0
package/README.md
CHANGED
|
@@ -21,30 +21,52 @@ Thought Cabinet solves these by providing:
|
|
|
21
21
|
## Quick Start
|
|
22
22
|
|
|
23
23
|
```bash
|
|
24
|
-
cd your-project
|
|
25
|
-
|
|
26
24
|
# 1. Install
|
|
27
25
|
pnpm install -g thought-cabinet
|
|
28
26
|
|
|
29
|
-
# 2.
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
# 3. Install skills to your AI agent
|
|
27
|
+
# 2. Install skills to your AI agent
|
|
28
|
+
cd your-project
|
|
33
29
|
thc skill install
|
|
34
30
|
|
|
35
|
-
#
|
|
31
|
+
# 3. Onboard the project (in your agent session)
|
|
32
|
+
> /onboard
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The `/onboard` skill initializes thoughts, creates agent memory (`AGENTS.md`), and installs git hooks — all in one step.
|
|
36
|
+
|
|
37
|
+
Once onboarded, use the workflow skills:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
36
40
|
> /research-codebase How does the authentication system work?
|
|
37
41
|
> /creating-plan Add OAuth2 support based on the research
|
|
38
42
|
> /implementing-plan thoughts/shared/plans/add-oauth.md
|
|
39
43
|
> /validating-plan thoughts/shared/plans/add-oauth.md
|
|
40
44
|
```
|
|
41
45
|
|
|
46
|
+
<details>
|
|
47
|
+
<summary>Manual setup (without the onboard skill)</summary>
|
|
48
|
+
|
|
49
|
+
If you prefer to set up manually instead of using `/onboard`:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
cd your-project
|
|
53
|
+
|
|
54
|
+
# Initialize thoughts
|
|
55
|
+
thc init
|
|
56
|
+
|
|
57
|
+
# Install skills to your AI agent
|
|
58
|
+
thc skill install
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
</details>
|
|
62
|
+
|
|
42
63
|
## Skills
|
|
43
64
|
|
|
44
65
|
Skills are installed by `thc skill install` and invoked as slash commands in your agent session:
|
|
45
66
|
|
|
46
67
|
| Skill | Description |
|
|
47
68
|
| -------------------- | --------------------------------------------------------------------- |
|
|
69
|
+
| `/onboard` | Initialize thoughts and bootstrap agent memory for a new project |
|
|
48
70
|
| `/research-codebase` | Deep-dive into codebase, save findings to `thoughts/shared/research/` |
|
|
49
71
|
| `/creating-plan` | Create implementation plan with phases and success criteria |
|
|
50
72
|
| `/iterating-plan` | Refine existing plans based on feedback |
|
package/dist/index.js
CHANGED
|
@@ -1095,81 +1095,92 @@ async function thoughtsInitCommand(options) {
|
|
|
1095
1095
|
}
|
|
1096
1096
|
let config = loadThoughtsConfig(options);
|
|
1097
1097
|
if (!config) {
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
message: "Directory name for repository-specific thoughts:",
|
|
1119
|
-
initialValue: "repos",
|
|
1120
|
-
placeholder: "repos"
|
|
1121
|
-
});
|
|
1122
|
-
if (p.isCancel(reposDirInput)) {
|
|
1123
|
-
p.cancel("Operation cancelled.");
|
|
1124
|
-
process.exit(0);
|
|
1125
|
-
}
|
|
1126
|
-
const reposDir2 = reposDirInput || "repos";
|
|
1127
|
-
const globalDirInput = await p.text({
|
|
1128
|
-
message: "Directory name for global thoughts:",
|
|
1129
|
-
initialValue: "global",
|
|
1130
|
-
placeholder: "global"
|
|
1131
|
-
});
|
|
1132
|
-
if (p.isCancel(globalDirInput)) {
|
|
1133
|
-
p.cancel("Operation cancelled.");
|
|
1134
|
-
process.exit(0);
|
|
1135
|
-
}
|
|
1136
|
-
const globalDir = globalDirInput || "global";
|
|
1137
|
-
const defaultUser = process.env.USER || "user";
|
|
1138
|
-
let user = "";
|
|
1139
|
-
while (!user || user.toLowerCase() === "global") {
|
|
1140
|
-
const userInput = await p.text({
|
|
1141
|
-
message: "Your username:",
|
|
1142
|
-
initialValue: defaultUser,
|
|
1143
|
-
placeholder: defaultUser,
|
|
1144
|
-
validate: (value) => {
|
|
1145
|
-
if (value.toLowerCase() === "global") {
|
|
1146
|
-
return `Username cannot be "global" as it's reserved for cross-project thoughts.`;
|
|
1147
|
-
}
|
|
1148
|
-
return void 0;
|
|
1149
|
-
}
|
|
1098
|
+
if (options.directory) {
|
|
1099
|
+
const thoughtsRepo = getDefaultThoughtsRepo();
|
|
1100
|
+
const reposDir2 = "repos";
|
|
1101
|
+
const globalDir = "global";
|
|
1102
|
+
const user = process.env.USER || "user";
|
|
1103
|
+
config = { thoughtsRepo, reposDir: reposDir2, globalDir, user, repoMappings: {} };
|
|
1104
|
+
ensureThoughtsRepoExists(thoughtsRepo, reposDir2, globalDir);
|
|
1105
|
+
saveThoughtsConfig(config, options);
|
|
1106
|
+
p.log.success("Global thoughts configuration created with defaults");
|
|
1107
|
+
} else {
|
|
1108
|
+
p.intro(chalk5.blue("Initial Thoughts Setup"));
|
|
1109
|
+
p.log.info("First, let's configure your global thoughts system.");
|
|
1110
|
+
const defaultRepo = getDefaultThoughtsRepo();
|
|
1111
|
+
p.log.message(
|
|
1112
|
+
chalk5.gray("This is where all your thoughts across all projects will be stored.")
|
|
1113
|
+
);
|
|
1114
|
+
const thoughtsRepoInput = await p.text({
|
|
1115
|
+
message: "Thoughts repository location:",
|
|
1116
|
+
initialValue: defaultRepo,
|
|
1117
|
+
placeholder: defaultRepo
|
|
1150
1118
|
});
|
|
1151
|
-
if (p.isCancel(
|
|
1119
|
+
if (p.isCancel(thoughtsRepoInput)) {
|
|
1152
1120
|
p.cancel("Operation cancelled.");
|
|
1153
1121
|
process.exit(0);
|
|
1154
1122
|
}
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1123
|
+
const thoughtsRepo = thoughtsRepoInput || defaultRepo;
|
|
1124
|
+
p.log.message(chalk5.gray("Your thoughts will be organized into two main directories:"));
|
|
1125
|
+
p.log.message(chalk5.gray("- Repository-specific thoughts (one subdirectory per project)"));
|
|
1126
|
+
p.log.message(chalk5.gray("- Global thoughts (shared across all projects)"));
|
|
1127
|
+
const reposDirInput = await p.text({
|
|
1128
|
+
message: "Directory name for repository-specific thoughts:",
|
|
1129
|
+
initialValue: "repos",
|
|
1130
|
+
placeholder: "repos"
|
|
1131
|
+
});
|
|
1132
|
+
if (p.isCancel(reposDirInput)) {
|
|
1133
|
+
p.cancel("Operation cancelled.");
|
|
1134
|
+
process.exit(0);
|
|
1135
|
+
}
|
|
1136
|
+
const reposDir2 = reposDirInput || "repos";
|
|
1137
|
+
const globalDirInput = await p.text({
|
|
1138
|
+
message: "Directory name for global thoughts:",
|
|
1139
|
+
initialValue: "global",
|
|
1140
|
+
placeholder: "global"
|
|
1141
|
+
});
|
|
1142
|
+
if (p.isCancel(globalDirInput)) {
|
|
1143
|
+
p.cancel("Operation cancelled.");
|
|
1144
|
+
process.exit(0);
|
|
1145
|
+
}
|
|
1146
|
+
const globalDir = globalDirInput || "global";
|
|
1147
|
+
const defaultUser = process.env.USER || "user";
|
|
1148
|
+
let user = "";
|
|
1149
|
+
while (!user || user.toLowerCase() === "global") {
|
|
1150
|
+
const userInput = await p.text({
|
|
1151
|
+
message: "Your username:",
|
|
1152
|
+
initialValue: defaultUser,
|
|
1153
|
+
placeholder: defaultUser,
|
|
1154
|
+
validate: (value) => {
|
|
1155
|
+
if (value.toLowerCase() === "global") {
|
|
1156
|
+
return `Username cannot be "global" as it's reserved for cross-project thoughts.`;
|
|
1157
|
+
}
|
|
1158
|
+
return void 0;
|
|
1159
|
+
}
|
|
1160
|
+
});
|
|
1161
|
+
if (p.isCancel(userInput)) {
|
|
1162
|
+
p.cancel("Operation cancelled.");
|
|
1163
|
+
process.exit(0);
|
|
1164
|
+
}
|
|
1165
|
+
user = userInput || defaultUser;
|
|
1166
|
+
}
|
|
1167
|
+
config = {
|
|
1168
|
+
thoughtsRepo,
|
|
1169
|
+
reposDir: reposDir2,
|
|
1170
|
+
globalDir,
|
|
1171
|
+
user,
|
|
1172
|
+
repoMappings: {}
|
|
1173
|
+
};
|
|
1174
|
+
p.note(
|
|
1175
|
+
`${chalk5.cyan(thoughtsRepo)}/
|
|
1166
1176
|
\u251C\u2500\u2500 ${chalk5.cyan(reposDir2)}/ ${chalk5.gray("(project-specific thoughts)")}
|
|
1167
1177
|
\u2514\u2500\u2500 ${chalk5.cyan(globalDir)}/ ${chalk5.gray("(cross-project thoughts)")}`,
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1178
|
+
"Creating thoughts structure"
|
|
1179
|
+
);
|
|
1180
|
+
ensureThoughtsRepoExists(thoughtsRepo, reposDir2, globalDir);
|
|
1181
|
+
saveThoughtsConfig(config, options);
|
|
1182
|
+
p.log.success("Global thoughts configuration created");
|
|
1183
|
+
}
|
|
1173
1184
|
}
|
|
1174
1185
|
if (options.profile) {
|
|
1175
1186
|
if (!validateProfile(config, options.profile)) {
|
|
@@ -1261,18 +1272,16 @@ async function thoughtsInitCommand(options) {
|
|
|
1261
1272
|
if (!mappedName) {
|
|
1262
1273
|
if (options.directory) {
|
|
1263
1274
|
const sanitizedDir = sanitizeDirectoryName(options.directory);
|
|
1264
|
-
if (
|
|
1265
|
-
p.log.
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1275
|
+
if (existingRepos.includes(sanitizedDir)) {
|
|
1276
|
+
p.log.success(
|
|
1277
|
+
`Using existing: ${tempProfileConfig.thoughtsRepo}/${tempProfileConfig.reposDir}/${sanitizedDir}`
|
|
1278
|
+
);
|
|
1279
|
+
} else {
|
|
1280
|
+
p.log.success(
|
|
1281
|
+
`Will create: ${tempProfileConfig.thoughtsRepo}/${tempProfileConfig.reposDir}/${sanitizedDir}`
|
|
1282
|
+
);
|
|
1271
1283
|
}
|
|
1272
1284
|
mappedName = sanitizedDir;
|
|
1273
|
-
p.log.success(
|
|
1274
|
-
`Using existing: ${tempProfileConfig.thoughtsRepo}/${tempProfileConfig.reposDir}/${mappedName}`
|
|
1275
|
-
);
|
|
1276
1285
|
} else {
|
|
1277
1286
|
p.intro(chalk5.blue("Repository Setup"));
|
|
1278
1287
|
p.log.info(`Setting up thoughts for: ${chalk5.cyan(currentRepo)}`);
|