@claudetools/tools 0.3.0 → 0.3.2
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/cli.js +1 -0
- package/dist/setup.js +113 -41
- package/package.json +1 -1
package/dist/cli.js
CHANGED
package/dist/setup.js
CHANGED
|
@@ -7,8 +7,9 @@ import chalk from 'chalk';
|
|
|
7
7
|
import ora from 'ora';
|
|
8
8
|
import { homedir, hostname, platform } from 'os';
|
|
9
9
|
import { join, basename } from 'path';
|
|
10
|
-
import { existsSync, readFileSync, writeFileSync, mkdirSync, copyFileSync } from 'fs';
|
|
10
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync, copyFileSync, realpathSync } from 'fs';
|
|
11
11
|
import { randomUUID } from 'crypto';
|
|
12
|
+
import { execSync } from 'child_process';
|
|
12
13
|
import { loadConfigFromFile, saveConfig, ensureConfigDir, getConfigPath, DEFAULT_CONFIG, } from './helpers/config-manager.js';
|
|
13
14
|
import { GLOBAL_TEMPLATE, SECTION_START, SECTION_END, getProjectTemplate, } from './templates/claude-md.js';
|
|
14
15
|
// -----------------------------------------------------------------------------
|
|
@@ -110,6 +111,29 @@ function initializeProjectsFile() {
|
|
|
110
111
|
}, null, 2));
|
|
111
112
|
}
|
|
112
113
|
}
|
|
114
|
+
/**
|
|
115
|
+
* Detect git remote for a directory (secure implementation)
|
|
116
|
+
*/
|
|
117
|
+
function detectGitRemote(localPath) {
|
|
118
|
+
try {
|
|
119
|
+
// Resolve symlinks and validate path to prevent path traversal attacks
|
|
120
|
+
const resolvedPath = realpathSync(localPath);
|
|
121
|
+
// Ensure path is absolute and doesn't contain path traversal
|
|
122
|
+
if (!resolvedPath.startsWith('/') || resolvedPath.includes('..')) {
|
|
123
|
+
return undefined;
|
|
124
|
+
}
|
|
125
|
+
const gitRemote = execSync('git config --get remote.origin.url', {
|
|
126
|
+
cwd: resolvedPath,
|
|
127
|
+
encoding: 'utf-8',
|
|
128
|
+
stdio: ['pipe', 'pipe', 'ignore'],
|
|
129
|
+
}).trim();
|
|
130
|
+
return gitRemote || undefined;
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
// Not a git repo or no remote configured
|
|
134
|
+
return undefined;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
113
137
|
// -----------------------------------------------------------------------------
|
|
114
138
|
// Authentication
|
|
115
139
|
// -----------------------------------------------------------------------------
|
|
@@ -1088,58 +1112,106 @@ export async function runInit() {
|
|
|
1088
1112
|
error('ClaudeTools not configured. Run "claudetools --setup" first.');
|
|
1089
1113
|
process.exit(1);
|
|
1090
1114
|
}
|
|
1115
|
+
// Load system info
|
|
1116
|
+
const systemInfo = loadSystemInfo();
|
|
1117
|
+
if (!systemInfo?.system_id) {
|
|
1118
|
+
error('System not registered. Run "claudetools --setup" first.');
|
|
1119
|
+
process.exit(1);
|
|
1120
|
+
}
|
|
1121
|
+
// Detect git remote for this directory
|
|
1122
|
+
const gitRemote = detectGitRemote(cwd);
|
|
1091
1123
|
// Try to register project with API
|
|
1092
1124
|
const spinner = ora('Registering project...').start();
|
|
1093
1125
|
let projectId;
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
const
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1126
|
+
// Use auto-bind endpoint if git remote exists
|
|
1127
|
+
if (gitRemote) {
|
|
1128
|
+
try {
|
|
1129
|
+
const response = await fetch(`${config.apiUrl || DEFAULT_CONFIG.apiUrl}/api/v1/systems/${systemInfo.system_id}/bindings/auto`, {
|
|
1130
|
+
method: 'POST',
|
|
1131
|
+
headers: {
|
|
1132
|
+
'Content-Type': 'application/json',
|
|
1133
|
+
'Authorization': `Bearer ${config.apiKey}`,
|
|
1134
|
+
},
|
|
1135
|
+
body: JSON.stringify({
|
|
1136
|
+
local_path: cwd,
|
|
1137
|
+
git_remote: gitRemote,
|
|
1138
|
+
project_name: projectName,
|
|
1139
|
+
}),
|
|
1140
|
+
});
|
|
1141
|
+
if (response.ok) {
|
|
1142
|
+
const data = await response.json();
|
|
1143
|
+
projectId = data.data?.project_id || `local_${projectName.toLowerCase().replace(/[^a-z0-9]/g, '_')}`;
|
|
1144
|
+
const registeredName = data.data?.project_name || projectName;
|
|
1145
|
+
spinner.succeed(`Registered project: ${registeredName} (${projectId})`);
|
|
1146
|
+
// Update local projects.json
|
|
1147
|
+
try {
|
|
1148
|
+
const projectsData = existsSync(PROJECTS_FILE)
|
|
1149
|
+
? JSON.parse(readFileSync(PROJECTS_FILE, 'utf-8'))
|
|
1150
|
+
: { bindings: [], system_id: systemInfo.system_id };
|
|
1151
|
+
// Check if already in bindings
|
|
1152
|
+
const existingIdx = projectsData.bindings.findIndex((b) => b.local_path === cwd);
|
|
1153
|
+
if (existingIdx >= 0) {
|
|
1154
|
+
projectsData.bindings[existingIdx].project_id = projectId;
|
|
1155
|
+
projectsData.bindings[existingIdx].project_name = registeredName;
|
|
1156
|
+
projectsData.bindings[existingIdx].git_remote = gitRemote;
|
|
1157
|
+
}
|
|
1158
|
+
else {
|
|
1159
|
+
projectsData.bindings.push({
|
|
1160
|
+
project_id: projectId,
|
|
1161
|
+
local_path: cwd,
|
|
1162
|
+
project_name: registeredName,
|
|
1163
|
+
git_remote: gitRemote,
|
|
1164
|
+
system_id: systemInfo.system_id,
|
|
1165
|
+
cached_at: new Date().toISOString(),
|
|
1166
|
+
});
|
|
1167
|
+
}
|
|
1168
|
+
projectsData.last_sync = new Date().toISOString();
|
|
1169
|
+
writeFileSync(PROJECTS_FILE, JSON.stringify(projectsData, null, 2));
|
|
1119
1170
|
}
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
project_id: projectId,
|
|
1123
|
-
local_path: cwd,
|
|
1124
|
-
project_name: projectName,
|
|
1125
|
-
cached_at: new Date().toISOString(),
|
|
1126
|
-
});
|
|
1171
|
+
catch {
|
|
1172
|
+
// Non-fatal
|
|
1127
1173
|
}
|
|
1128
|
-
projectsData.last_sync = new Date().toISOString();
|
|
1129
|
-
writeFileSync(PROJECTS_FILE, JSON.stringify(projectsData, null, 2));
|
|
1130
1174
|
}
|
|
1131
|
-
|
|
1132
|
-
|
|
1175
|
+
else {
|
|
1176
|
+
const errorData = await response.json().catch(() => ({}));
|
|
1177
|
+
spinner.warn(`Could not register with API: ${errorData.error || response.status}`);
|
|
1178
|
+
projectId = `local_${projectName.toLowerCase().replace(/[^a-z0-9]/g, '_')}`;
|
|
1133
1179
|
}
|
|
1134
1180
|
}
|
|
1135
|
-
|
|
1136
|
-
spinner.warn('Could not
|
|
1181
|
+
catch (err) {
|
|
1182
|
+
spinner.warn('Could not reach API, using local ID');
|
|
1137
1183
|
projectId = `local_${projectName.toLowerCase().replace(/[^a-z0-9]/g, '_')}`;
|
|
1138
1184
|
}
|
|
1139
1185
|
}
|
|
1140
|
-
|
|
1141
|
-
|
|
1186
|
+
else {
|
|
1187
|
+
// No git remote - use local ID
|
|
1188
|
+
spinner.info('No git remote detected, using local project ID');
|
|
1142
1189
|
projectId = `local_${projectName.toLowerCase().replace(/[^a-z0-9]/g, '_')}`;
|
|
1190
|
+
// Still update local projects.json for session context
|
|
1191
|
+
try {
|
|
1192
|
+
const projectsData = existsSync(PROJECTS_FILE)
|
|
1193
|
+
? JSON.parse(readFileSync(PROJECTS_FILE, 'utf-8'))
|
|
1194
|
+
: { bindings: [], system_id: systemInfo.system_id };
|
|
1195
|
+
const existingIdx = projectsData.bindings.findIndex((b) => b.local_path === cwd);
|
|
1196
|
+
if (existingIdx >= 0) {
|
|
1197
|
+
projectsData.bindings[existingIdx].project_id = projectId;
|
|
1198
|
+
projectsData.bindings[existingIdx].project_name = projectName;
|
|
1199
|
+
}
|
|
1200
|
+
else {
|
|
1201
|
+
projectsData.bindings.push({
|
|
1202
|
+
project_id: projectId,
|
|
1203
|
+
local_path: cwd,
|
|
1204
|
+
project_name: projectName,
|
|
1205
|
+
system_id: systemInfo.system_id,
|
|
1206
|
+
cached_at: new Date().toISOString(),
|
|
1207
|
+
});
|
|
1208
|
+
}
|
|
1209
|
+
projectsData.last_sync = new Date().toISOString();
|
|
1210
|
+
writeFileSync(PROJECTS_FILE, JSON.stringify(projectsData, null, 2));
|
|
1211
|
+
}
|
|
1212
|
+
catch {
|
|
1213
|
+
// Non-fatal
|
|
1214
|
+
}
|
|
1143
1215
|
}
|
|
1144
1216
|
// Create .claude directory if needed
|
|
1145
1217
|
if (!existsSync(projectClaudeDir)) {
|