@skillkit/core 1.17.0 → 1.18.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/dist/index.d.ts +152 -1
- package/dist/index.js +1657 -1103
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -7955,6 +7955,837 @@ function getMostRecentSession() {
|
|
|
7955
7955
|
return loadSessionFile(summaries[0].date);
|
|
7956
7956
|
}
|
|
7957
7957
|
|
|
7958
|
+
// src/session/activity-log.ts
|
|
7959
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync9, readFileSync as readFileSync10, writeFileSync as writeFileSync9 } from "fs";
|
|
7960
|
+
import { join as join17 } from "path";
|
|
7961
|
+
import { parse as parse2, stringify as stringify2 } from "yaml";
|
|
7962
|
+
var ACTIVITY_FILE = "activity.yaml";
|
|
7963
|
+
var ActivityLog = class {
|
|
7964
|
+
filePath;
|
|
7965
|
+
projectPath;
|
|
7966
|
+
data = null;
|
|
7967
|
+
constructor(projectPath) {
|
|
7968
|
+
this.projectPath = projectPath;
|
|
7969
|
+
this.filePath = join17(projectPath, ".skillkit", ACTIVITY_FILE);
|
|
7970
|
+
}
|
|
7971
|
+
createEmpty() {
|
|
7972
|
+
return { version: 1, activities: [] };
|
|
7973
|
+
}
|
|
7974
|
+
load() {
|
|
7975
|
+
if (this.data) return this.data;
|
|
7976
|
+
if (!existsSync18(this.filePath)) {
|
|
7977
|
+
this.data = this.createEmpty();
|
|
7978
|
+
return this.data;
|
|
7979
|
+
}
|
|
7980
|
+
try {
|
|
7981
|
+
const content = readFileSync10(this.filePath, "utf-8");
|
|
7982
|
+
const parsed = parse2(content);
|
|
7983
|
+
if (parsed && Array.isArray(parsed.activities)) {
|
|
7984
|
+
this.data = parsed;
|
|
7985
|
+
} else {
|
|
7986
|
+
this.data = this.createEmpty();
|
|
7987
|
+
}
|
|
7988
|
+
} catch {
|
|
7989
|
+
this.data = this.createEmpty();
|
|
7990
|
+
}
|
|
7991
|
+
return this.data;
|
|
7992
|
+
}
|
|
7993
|
+
save() {
|
|
7994
|
+
const dir = join17(this.projectPath, ".skillkit");
|
|
7995
|
+
if (!existsSync18(dir)) {
|
|
7996
|
+
mkdirSync9(dir, { recursive: true });
|
|
7997
|
+
}
|
|
7998
|
+
writeFileSync9(this.filePath, stringify2(this.data));
|
|
7999
|
+
}
|
|
8000
|
+
record(entry) {
|
|
8001
|
+
const data = this.load();
|
|
8002
|
+
data.activities.unshift({
|
|
8003
|
+
commitSha: entry.commitSha,
|
|
8004
|
+
committedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8005
|
+
activeSkills: entry.activeSkills,
|
|
8006
|
+
filesChanged: entry.filesChanged,
|
|
8007
|
+
message: entry.message
|
|
8008
|
+
});
|
|
8009
|
+
if (data.activities.length > 500) {
|
|
8010
|
+
data.activities = data.activities.slice(0, 500);
|
|
8011
|
+
}
|
|
8012
|
+
this.save();
|
|
8013
|
+
}
|
|
8014
|
+
getByCommit(sha) {
|
|
8015
|
+
if (sha.length < 4) return void 0;
|
|
8016
|
+
const data = this.load();
|
|
8017
|
+
return data.activities.find(
|
|
8018
|
+
(a) => a.commitSha === sha || a.commitSha.startsWith(sha)
|
|
8019
|
+
);
|
|
8020
|
+
}
|
|
8021
|
+
getBySkill(skillName) {
|
|
8022
|
+
const data = this.load();
|
|
8023
|
+
return data.activities.filter((a) => a.activeSkills.includes(skillName));
|
|
8024
|
+
}
|
|
8025
|
+
getRecent(limit = 20) {
|
|
8026
|
+
const data = this.load();
|
|
8027
|
+
return data.activities.slice(0, limit);
|
|
8028
|
+
}
|
|
8029
|
+
getMostUsedSkills() {
|
|
8030
|
+
const data = this.load();
|
|
8031
|
+
const counts = /* @__PURE__ */ new Map();
|
|
8032
|
+
for (const activity of data.activities) {
|
|
8033
|
+
for (const skill of activity.activeSkills) {
|
|
8034
|
+
counts.set(skill, (counts.get(skill) ?? 0) + 1);
|
|
8035
|
+
}
|
|
8036
|
+
}
|
|
8037
|
+
return Array.from(counts.entries()).map(([skill, count]) => ({ skill, count })).sort((a, b) => b.count - a.count);
|
|
8038
|
+
}
|
|
8039
|
+
};
|
|
8040
|
+
|
|
8041
|
+
// src/session/snapshot-manager.ts
|
|
8042
|
+
import {
|
|
8043
|
+
existsSync as existsSync19,
|
|
8044
|
+
mkdirSync as mkdirSync10,
|
|
8045
|
+
readFileSync as readFileSync11,
|
|
8046
|
+
writeFileSync as writeFileSync10,
|
|
8047
|
+
readdirSync as readdirSync5,
|
|
8048
|
+
unlinkSync as unlinkSync2
|
|
8049
|
+
} from "fs";
|
|
8050
|
+
import { join as join18 } from "path";
|
|
8051
|
+
import { parse as parse3, stringify as stringify3 } from "yaml";
|
|
8052
|
+
var SAFE_NAME_RE = /^[a-zA-Z0-9_-]+$/;
|
|
8053
|
+
var SnapshotManager = class {
|
|
8054
|
+
snapshotsDir;
|
|
8055
|
+
constructor(projectPath) {
|
|
8056
|
+
this.snapshotsDir = join18(projectPath, ".skillkit", "snapshots");
|
|
8057
|
+
}
|
|
8058
|
+
ensureDir() {
|
|
8059
|
+
if (!existsSync19(this.snapshotsDir)) {
|
|
8060
|
+
mkdirSync10(this.snapshotsDir, { recursive: true });
|
|
8061
|
+
}
|
|
8062
|
+
}
|
|
8063
|
+
sanitizeName(name) {
|
|
8064
|
+
if (!name || !SAFE_NAME_RE.test(name)) {
|
|
8065
|
+
throw new Error(`Invalid snapshot name: "${name}". Use only letters, numbers, hyphens, and underscores.`);
|
|
8066
|
+
}
|
|
8067
|
+
return name;
|
|
8068
|
+
}
|
|
8069
|
+
getPath(name) {
|
|
8070
|
+
const safe = this.sanitizeName(name);
|
|
8071
|
+
return join18(this.snapshotsDir, `${safe}.yaml`);
|
|
8072
|
+
}
|
|
8073
|
+
save(name, sessionState, observations, description) {
|
|
8074
|
+
this.ensureDir();
|
|
8075
|
+
const snapshot = {
|
|
8076
|
+
version: 1,
|
|
8077
|
+
name,
|
|
8078
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8079
|
+
description,
|
|
8080
|
+
sessionState,
|
|
8081
|
+
observations
|
|
8082
|
+
};
|
|
8083
|
+
writeFileSync10(this.getPath(name), stringify3(snapshot));
|
|
8084
|
+
}
|
|
8085
|
+
restore(name) {
|
|
8086
|
+
const filepath = this.getPath(name);
|
|
8087
|
+
if (!existsSync19(filepath)) {
|
|
8088
|
+
throw new Error(`Snapshot "${name}" not found`);
|
|
8089
|
+
}
|
|
8090
|
+
let snapshot;
|
|
8091
|
+
try {
|
|
8092
|
+
const content = readFileSync11(filepath, "utf-8");
|
|
8093
|
+
snapshot = parse3(content);
|
|
8094
|
+
} catch (err) {
|
|
8095
|
+
throw new Error(`Failed to read snapshot "${name}": ${err instanceof Error ? err.message : "unknown error"}`);
|
|
8096
|
+
}
|
|
8097
|
+
if (!snapshot.sessionState || !snapshot.observations) {
|
|
8098
|
+
throw new Error(`Snapshot "${name}" is corrupted or invalid`);
|
|
8099
|
+
}
|
|
8100
|
+
return {
|
|
8101
|
+
sessionState: snapshot.sessionState,
|
|
8102
|
+
observations: snapshot.observations
|
|
8103
|
+
};
|
|
8104
|
+
}
|
|
8105
|
+
list() {
|
|
8106
|
+
if (!existsSync19(this.snapshotsDir)) {
|
|
8107
|
+
return [];
|
|
8108
|
+
}
|
|
8109
|
+
const files = readdirSync5(this.snapshotsDir).filter(
|
|
8110
|
+
(f) => f.endsWith(".yaml")
|
|
8111
|
+
);
|
|
8112
|
+
return files.map((f) => {
|
|
8113
|
+
try {
|
|
8114
|
+
const content = readFileSync11(join18(this.snapshotsDir, f), "utf-8");
|
|
8115
|
+
const snapshot = parse3(content);
|
|
8116
|
+
if (!snapshot.createdAt) {
|
|
8117
|
+
return null;
|
|
8118
|
+
}
|
|
8119
|
+
const skillCount = snapshot.sessionState?.history?.length ?? 0;
|
|
8120
|
+
return {
|
|
8121
|
+
name: snapshot.name ?? f.replace(/\.yaml$/, ""),
|
|
8122
|
+
createdAt: snapshot.createdAt,
|
|
8123
|
+
description: snapshot.description,
|
|
8124
|
+
skillCount
|
|
8125
|
+
};
|
|
8126
|
+
} catch {
|
|
8127
|
+
return null;
|
|
8128
|
+
}
|
|
8129
|
+
}).filter((s) => s !== null).sort((a, b) => {
|
|
8130
|
+
const timeA = new Date(a.createdAt).getTime() || 0;
|
|
8131
|
+
const timeB = new Date(b.createdAt).getTime() || 0;
|
|
8132
|
+
return timeB - timeA;
|
|
8133
|
+
});
|
|
8134
|
+
}
|
|
8135
|
+
get(name) {
|
|
8136
|
+
const filepath = this.getPath(name);
|
|
8137
|
+
if (!existsSync19(filepath)) {
|
|
8138
|
+
return void 0;
|
|
8139
|
+
}
|
|
8140
|
+
try {
|
|
8141
|
+
const content = readFileSync11(filepath, "utf-8");
|
|
8142
|
+
return parse3(content);
|
|
8143
|
+
} catch {
|
|
8144
|
+
return void 0;
|
|
8145
|
+
}
|
|
8146
|
+
}
|
|
8147
|
+
delete(name) {
|
|
8148
|
+
const filepath = this.getPath(name);
|
|
8149
|
+
if (!existsSync19(filepath)) {
|
|
8150
|
+
return false;
|
|
8151
|
+
}
|
|
8152
|
+
unlinkSync2(filepath);
|
|
8153
|
+
return true;
|
|
8154
|
+
}
|
|
8155
|
+
exists(name) {
|
|
8156
|
+
return existsSync19(this.getPath(name));
|
|
8157
|
+
}
|
|
8158
|
+
};
|
|
8159
|
+
|
|
8160
|
+
// src/memory/observation-store.ts
|
|
8161
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync11, readFileSync as readFileSync12, writeFileSync as writeFileSync11 } from "fs";
|
|
8162
|
+
import { dirname as dirname4, join as join19 } from "path";
|
|
8163
|
+
import { parse as parseYaml6, stringify as stringifyYaml5 } from "yaml";
|
|
8164
|
+
import { randomUUID as randomUUID6 } from "crypto";
|
|
8165
|
+
var ObservationStore = class {
|
|
8166
|
+
filePath;
|
|
8167
|
+
projectPath;
|
|
8168
|
+
data = null;
|
|
8169
|
+
sessionId;
|
|
8170
|
+
compressionThreshold;
|
|
8171
|
+
autoCompress;
|
|
8172
|
+
onThresholdReached;
|
|
8173
|
+
compressionInProgress = false;
|
|
8174
|
+
constructor(projectPath, sessionId, options = {}) {
|
|
8175
|
+
this.projectPath = projectPath;
|
|
8176
|
+
this.filePath = join19(projectPath, ".skillkit", "memory", "observations.yaml");
|
|
8177
|
+
this.sessionId = sessionId || randomUUID6();
|
|
8178
|
+
this.compressionThreshold = options.compressionThreshold ?? 50;
|
|
8179
|
+
this.autoCompress = options.autoCompress ?? true;
|
|
8180
|
+
this.onThresholdReached = options.onThresholdReached;
|
|
8181
|
+
}
|
|
8182
|
+
ensureDir() {
|
|
8183
|
+
const dir = dirname4(this.filePath);
|
|
8184
|
+
if (!existsSync20(dir)) {
|
|
8185
|
+
mkdirSync11(dir, { recursive: true });
|
|
8186
|
+
}
|
|
8187
|
+
}
|
|
8188
|
+
load() {
|
|
8189
|
+
if (this.data) return this.data;
|
|
8190
|
+
if (existsSync20(this.filePath)) {
|
|
8191
|
+
try {
|
|
8192
|
+
const content = readFileSync12(this.filePath, "utf-8");
|
|
8193
|
+
this.data = parseYaml6(content);
|
|
8194
|
+
if (this.data.sessionId !== this.sessionId) {
|
|
8195
|
+
this.data.sessionId = this.sessionId;
|
|
8196
|
+
this.data.observations = [];
|
|
8197
|
+
}
|
|
8198
|
+
} catch {
|
|
8199
|
+
this.data = this.createEmpty();
|
|
8200
|
+
}
|
|
8201
|
+
} else {
|
|
8202
|
+
this.data = this.createEmpty();
|
|
8203
|
+
}
|
|
8204
|
+
return this.data;
|
|
8205
|
+
}
|
|
8206
|
+
createEmpty() {
|
|
8207
|
+
return {
|
|
8208
|
+
version: 1,
|
|
8209
|
+
sessionId: this.sessionId,
|
|
8210
|
+
observations: []
|
|
8211
|
+
};
|
|
8212
|
+
}
|
|
8213
|
+
save() {
|
|
8214
|
+
this.ensureDir();
|
|
8215
|
+
const content = stringifyYaml5(this.data, { lineWidth: 0 });
|
|
8216
|
+
writeFileSync11(this.filePath, content, "utf-8");
|
|
8217
|
+
}
|
|
8218
|
+
add(type, content, agent, relevance = 50) {
|
|
8219
|
+
const data = this.load();
|
|
8220
|
+
const observation = {
|
|
8221
|
+
id: randomUUID6(),
|
|
8222
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8223
|
+
sessionId: this.sessionId,
|
|
8224
|
+
agent,
|
|
8225
|
+
type,
|
|
8226
|
+
content,
|
|
8227
|
+
relevance
|
|
8228
|
+
};
|
|
8229
|
+
data.observations.push(observation);
|
|
8230
|
+
this.save();
|
|
8231
|
+
void this.checkAutoCompression().catch(() => {
|
|
8232
|
+
});
|
|
8233
|
+
return observation;
|
|
8234
|
+
}
|
|
8235
|
+
/**
|
|
8236
|
+
* Check if auto-compression should trigger
|
|
8237
|
+
*/
|
|
8238
|
+
async checkAutoCompression() {
|
|
8239
|
+
if (!this.autoCompress || this.compressionInProgress) return;
|
|
8240
|
+
if (!this.onThresholdReached) return;
|
|
8241
|
+
const count = this.count();
|
|
8242
|
+
if (count >= this.compressionThreshold) {
|
|
8243
|
+
this.compressionInProgress = true;
|
|
8244
|
+
try {
|
|
8245
|
+
const observations = this.getAll();
|
|
8246
|
+
await this.onThresholdReached(observations);
|
|
8247
|
+
} finally {
|
|
8248
|
+
this.compressionInProgress = false;
|
|
8249
|
+
}
|
|
8250
|
+
}
|
|
8251
|
+
}
|
|
8252
|
+
/**
|
|
8253
|
+
* Set auto-compression callback
|
|
8254
|
+
*/
|
|
8255
|
+
setAutoCompressCallback(callback) {
|
|
8256
|
+
this.onThresholdReached = callback;
|
|
8257
|
+
}
|
|
8258
|
+
/**
|
|
8259
|
+
* Enable/disable auto-compression
|
|
8260
|
+
*/
|
|
8261
|
+
setAutoCompress(enabled) {
|
|
8262
|
+
this.autoCompress = enabled;
|
|
8263
|
+
}
|
|
8264
|
+
/**
|
|
8265
|
+
* Set compression threshold
|
|
8266
|
+
*/
|
|
8267
|
+
setCompressionThreshold(threshold) {
|
|
8268
|
+
if (threshold < 1 || !Number.isInteger(threshold)) {
|
|
8269
|
+
throw new Error("Compression threshold must be a positive integer");
|
|
8270
|
+
}
|
|
8271
|
+
this.compressionThreshold = threshold;
|
|
8272
|
+
}
|
|
8273
|
+
/**
|
|
8274
|
+
* Get compression threshold
|
|
8275
|
+
*/
|
|
8276
|
+
getCompressionThreshold() {
|
|
8277
|
+
return this.compressionThreshold;
|
|
8278
|
+
}
|
|
8279
|
+
/**
|
|
8280
|
+
* Check if threshold is reached
|
|
8281
|
+
*/
|
|
8282
|
+
isThresholdReached() {
|
|
8283
|
+
return this.count() >= this.compressionThreshold;
|
|
8284
|
+
}
|
|
8285
|
+
/**
|
|
8286
|
+
* Get project path
|
|
8287
|
+
*/
|
|
8288
|
+
getProjectPath() {
|
|
8289
|
+
return this.projectPath;
|
|
8290
|
+
}
|
|
8291
|
+
getAll() {
|
|
8292
|
+
return this.load().observations;
|
|
8293
|
+
}
|
|
8294
|
+
static readAll(projectPath) {
|
|
8295
|
+
const filePath = join19(projectPath, ".skillkit", "memory", "observations.yaml");
|
|
8296
|
+
if (!existsSync20(filePath)) return [];
|
|
8297
|
+
try {
|
|
8298
|
+
const content = readFileSync12(filePath, "utf-8");
|
|
8299
|
+
const data = parseYaml6(content);
|
|
8300
|
+
return data?.observations ?? [];
|
|
8301
|
+
} catch {
|
|
8302
|
+
return [];
|
|
8303
|
+
}
|
|
8304
|
+
}
|
|
8305
|
+
getByType(type) {
|
|
8306
|
+
return this.load().observations.filter((o) => o.type === type);
|
|
8307
|
+
}
|
|
8308
|
+
getByRelevance(minRelevance) {
|
|
8309
|
+
return this.load().observations.filter((o) => o.relevance >= minRelevance);
|
|
8310
|
+
}
|
|
8311
|
+
getRecent(count) {
|
|
8312
|
+
const observations = this.load().observations;
|
|
8313
|
+
return observations.slice(-count);
|
|
8314
|
+
}
|
|
8315
|
+
getUncompressed(compressedIds) {
|
|
8316
|
+
const compressedSet = new Set(compressedIds);
|
|
8317
|
+
return this.load().observations.filter((o) => !compressedSet.has(o.id));
|
|
8318
|
+
}
|
|
8319
|
+
count() {
|
|
8320
|
+
return this.load().observations.length;
|
|
8321
|
+
}
|
|
8322
|
+
clear() {
|
|
8323
|
+
this.data = this.createEmpty();
|
|
8324
|
+
this.save();
|
|
8325
|
+
}
|
|
8326
|
+
getById(id) {
|
|
8327
|
+
return this.load().observations.find((o) => o.id === id);
|
|
8328
|
+
}
|
|
8329
|
+
getByIds(ids) {
|
|
8330
|
+
const idSet = new Set(ids);
|
|
8331
|
+
return this.load().observations.filter((o) => idSet.has(o.id));
|
|
8332
|
+
}
|
|
8333
|
+
getSessionId() {
|
|
8334
|
+
return this.sessionId;
|
|
8335
|
+
}
|
|
8336
|
+
setSessionId(sessionId) {
|
|
8337
|
+
this.sessionId = sessionId;
|
|
8338
|
+
if (this.data) {
|
|
8339
|
+
this.data.sessionId = sessionId;
|
|
8340
|
+
}
|
|
8341
|
+
}
|
|
8342
|
+
exists() {
|
|
8343
|
+
return existsSync20(this.filePath);
|
|
8344
|
+
}
|
|
8345
|
+
delete(id) {
|
|
8346
|
+
const data = this.load();
|
|
8347
|
+
const index = data.observations.findIndex((o) => o.id === id);
|
|
8348
|
+
if (index === -1) return false;
|
|
8349
|
+
data.observations.splice(index, 1);
|
|
8350
|
+
this.save();
|
|
8351
|
+
return true;
|
|
8352
|
+
}
|
|
8353
|
+
deleteMany(ids) {
|
|
8354
|
+
const idSet = new Set(ids);
|
|
8355
|
+
const data = this.load();
|
|
8356
|
+
const initialLength = data.observations.length;
|
|
8357
|
+
data.observations = data.observations.filter((o) => !idSet.has(o.id));
|
|
8358
|
+
if (data.observations.length !== initialLength) {
|
|
8359
|
+
this.save();
|
|
8360
|
+
}
|
|
8361
|
+
return initialLength - data.observations.length;
|
|
8362
|
+
}
|
|
8363
|
+
};
|
|
8364
|
+
|
|
8365
|
+
// src/learning/git-analyzer.ts
|
|
8366
|
+
import { execSync as execSync5 } from "child_process";
|
|
8367
|
+
import { existsSync as existsSync21 } from "fs";
|
|
8368
|
+
import { join as join20 } from "path";
|
|
8369
|
+
function runGitCommand(command, cwd) {
|
|
8370
|
+
try {
|
|
8371
|
+
return execSync5(command, { cwd, encoding: "utf-8", maxBuffer: 10 * 1024 * 1024 });
|
|
8372
|
+
} catch {
|
|
8373
|
+
return "";
|
|
8374
|
+
}
|
|
8375
|
+
}
|
|
8376
|
+
function isGitRepository(path4) {
|
|
8377
|
+
return existsSync21(join20(path4, ".git"));
|
|
8378
|
+
}
|
|
8379
|
+
function getGitCommits(repoPath, options = {}) {
|
|
8380
|
+
if (!isGitRepository(repoPath)) {
|
|
8381
|
+
return [];
|
|
8382
|
+
}
|
|
8383
|
+
const limit = options.commits || 100;
|
|
8384
|
+
const args = [
|
|
8385
|
+
"log",
|
|
8386
|
+
`--max-count=${limit}`,
|
|
8387
|
+
"--format=%H|||%h|||%an|||%aI|||%s|||%b|||END_COMMIT",
|
|
8388
|
+
"--name-status"
|
|
8389
|
+
];
|
|
8390
|
+
if (options.since) {
|
|
8391
|
+
args.push(`--since="${options.since}"`);
|
|
8392
|
+
}
|
|
8393
|
+
if (options.until) {
|
|
8394
|
+
args.push(`--until="${options.until}"`);
|
|
8395
|
+
}
|
|
8396
|
+
if (options.branch) {
|
|
8397
|
+
args.push(options.branch);
|
|
8398
|
+
}
|
|
8399
|
+
if (options.author) {
|
|
8400
|
+
args.push(`--author="${options.author}"`);
|
|
8401
|
+
}
|
|
8402
|
+
const output = runGitCommand(`git ${args.join(" ")}`, repoPath);
|
|
8403
|
+
if (!output) return [];
|
|
8404
|
+
const commits = [];
|
|
8405
|
+
const commitBlocks = output.split("END_COMMIT").filter((b) => b.trim());
|
|
8406
|
+
for (const block of commitBlocks) {
|
|
8407
|
+
const lines = block.trim().split("\n");
|
|
8408
|
+
if (lines.length === 0) continue;
|
|
8409
|
+
const headerLine = lines[0];
|
|
8410
|
+
const parts = headerLine.split("|||");
|
|
8411
|
+
if (parts.length < 5) continue;
|
|
8412
|
+
const [hash, shortHash, author, date, message, body] = parts;
|
|
8413
|
+
const files = [];
|
|
8414
|
+
for (let i = 1; i < lines.length; i++) {
|
|
8415
|
+
const line = lines[i].trim();
|
|
8416
|
+
if (!line) continue;
|
|
8417
|
+
const match = line.match(/^([AMDRT])\d*\t(.+?)(?:\t(.+))?$/);
|
|
8418
|
+
if (match) {
|
|
8419
|
+
const [, status, path4, oldPath] = match;
|
|
8420
|
+
files.push({
|
|
8421
|
+
path: path4,
|
|
8422
|
+
status: parseFileStatus(status),
|
|
8423
|
+
additions: 0,
|
|
8424
|
+
deletions: 0,
|
|
8425
|
+
oldPath: oldPath || void 0
|
|
8426
|
+
});
|
|
8427
|
+
}
|
|
8428
|
+
}
|
|
8429
|
+
commits.push({
|
|
8430
|
+
hash,
|
|
8431
|
+
shortHash,
|
|
8432
|
+
author,
|
|
8433
|
+
date,
|
|
8434
|
+
message,
|
|
8435
|
+
body: body || void 0,
|
|
8436
|
+
files
|
|
8437
|
+
});
|
|
8438
|
+
}
|
|
8439
|
+
return commits;
|
|
8440
|
+
}
|
|
8441
|
+
function parseFileStatus(status) {
|
|
8442
|
+
switch (status) {
|
|
8443
|
+
case "A":
|
|
8444
|
+
return "added";
|
|
8445
|
+
case "D":
|
|
8446
|
+
return "deleted";
|
|
8447
|
+
case "R":
|
|
8448
|
+
return "renamed";
|
|
8449
|
+
default:
|
|
8450
|
+
return "modified";
|
|
8451
|
+
}
|
|
8452
|
+
}
|
|
8453
|
+
function categorizeCommit(message, body) {
|
|
8454
|
+
const text = `${message} ${body || ""}`.toLowerCase();
|
|
8455
|
+
if (text.includes("fix") || text.includes("bug") || text.includes("error") || text.includes("issue")) {
|
|
8456
|
+
return "error_fix";
|
|
8457
|
+
}
|
|
8458
|
+
if (text.includes("refactor") || text.includes("clean") || text.includes("simplify")) {
|
|
8459
|
+
return "refactor";
|
|
8460
|
+
}
|
|
8461
|
+
if (text.includes("workaround") || text.includes("hack") || text.includes("temporary")) {
|
|
8462
|
+
return "workaround";
|
|
8463
|
+
}
|
|
8464
|
+
if (text.includes("debug") || text.includes("log") || text.includes("trace")) {
|
|
8465
|
+
return "debugging";
|
|
8466
|
+
}
|
|
8467
|
+
return null;
|
|
8468
|
+
}
|
|
8469
|
+
function shouldSkipCommit(commit, ignorePatterns) {
|
|
8470
|
+
const message = commit.message.toLowerCase();
|
|
8471
|
+
for (const pattern of ignorePatterns) {
|
|
8472
|
+
if (message.includes(pattern.toLowerCase())) {
|
|
8473
|
+
return true;
|
|
8474
|
+
}
|
|
8475
|
+
}
|
|
8476
|
+
if (message.startsWith("merge ") || message.startsWith("wip")) {
|
|
8477
|
+
return true;
|
|
8478
|
+
}
|
|
8479
|
+
if (commit.files.length === 0) {
|
|
8480
|
+
return true;
|
|
8481
|
+
}
|
|
8482
|
+
return false;
|
|
8483
|
+
}
|
|
8484
|
+
function extractPatternFromCommit(commit) {
|
|
8485
|
+
const category = categorizeCommit(commit.message, commit.body);
|
|
8486
|
+
if (!category) return null;
|
|
8487
|
+
const id = `git-${commit.shortHash}`;
|
|
8488
|
+
const title = formatTitle(commit.message);
|
|
8489
|
+
const problem = extractProblem(commit);
|
|
8490
|
+
const solution = extractSolution(commit);
|
|
8491
|
+
const context = extractContext(commit);
|
|
8492
|
+
if (!problem || !solution) return null;
|
|
8493
|
+
return {
|
|
8494
|
+
id,
|
|
8495
|
+
category,
|
|
8496
|
+
title,
|
|
8497
|
+
problem,
|
|
8498
|
+
solution,
|
|
8499
|
+
context,
|
|
8500
|
+
extractedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8501
|
+
source: "git",
|
|
8502
|
+
commitRange: { from: commit.hash, to: commit.hash },
|
|
8503
|
+
approved: false,
|
|
8504
|
+
confidence: calculateConfidence(commit, category)
|
|
8505
|
+
};
|
|
8506
|
+
}
|
|
8507
|
+
function formatTitle(message) {
|
|
8508
|
+
return message.charAt(0).toUpperCase() + message.slice(1);
|
|
8509
|
+
}
|
|
8510
|
+
function extractProblem(commit) {
|
|
8511
|
+
const message = commit.message.toLowerCase();
|
|
8512
|
+
if (message.includes("fix:") || message.includes("fix(")) {
|
|
8513
|
+
const match = commit.message.match(/fix[:(]\s*([^)]+)/i);
|
|
8514
|
+
if (match) {
|
|
8515
|
+
return `Issue: ${match[1]}`;
|
|
8516
|
+
}
|
|
8517
|
+
}
|
|
8518
|
+
if (commit.body) {
|
|
8519
|
+
const problemMatch = commit.body.match(/problem:?\s*(.+)/i);
|
|
8520
|
+
if (problemMatch) {
|
|
8521
|
+
return problemMatch[1].trim();
|
|
8522
|
+
}
|
|
8523
|
+
}
|
|
8524
|
+
return `${commit.message} (from commit ${commit.shortHash})`;
|
|
8525
|
+
}
|
|
8526
|
+
function extractSolution(commit) {
|
|
8527
|
+
if (commit.body) {
|
|
8528
|
+
const solutionMatch = commit.body.match(/solution:?\s*(.+)/i);
|
|
8529
|
+
if (solutionMatch) {
|
|
8530
|
+
return solutionMatch[1].trim();
|
|
8531
|
+
}
|
|
8532
|
+
}
|
|
8533
|
+
const files = commit.files.map((f) => f.path).join(", ");
|
|
8534
|
+
return `Modified: ${files}`;
|
|
8535
|
+
}
|
|
8536
|
+
function extractContext(commit) {
|
|
8537
|
+
const files = commit.files;
|
|
8538
|
+
const extensions = new Set(files.map((f) => f.path.split(".").pop() || ""));
|
|
8539
|
+
const directories = new Set(files.map((f) => f.path.split("/")[0]));
|
|
8540
|
+
const parts = [];
|
|
8541
|
+
if (extensions.size > 0) {
|
|
8542
|
+
parts.push(`Files: ${Array.from(extensions).filter((e) => e).join(", ")}`);
|
|
8543
|
+
}
|
|
8544
|
+
if (directories.size > 0 && directories.size <= 3) {
|
|
8545
|
+
parts.push(`Areas: ${Array.from(directories).join(", ")}`);
|
|
8546
|
+
}
|
|
8547
|
+
return parts.join(". ") || "General codebase";
|
|
8548
|
+
}
|
|
8549
|
+
function calculateConfidence(commit, category) {
|
|
8550
|
+
let confidence = 0.5;
|
|
8551
|
+
if (commit.body && commit.body.length > 50) {
|
|
8552
|
+
confidence += 0.1;
|
|
8553
|
+
}
|
|
8554
|
+
if (commit.message.match(/^(fix|feat|refactor|docs|test|chore)(\(.+\))?:/)) {
|
|
8555
|
+
confidence += 0.1;
|
|
8556
|
+
}
|
|
8557
|
+
if (commit.files.length > 0 && commit.files.length < 10) {
|
|
8558
|
+
confidence += 0.1;
|
|
8559
|
+
}
|
|
8560
|
+
if (category === "error_fix" || category === "workaround") {
|
|
8561
|
+
confidence += 0.05;
|
|
8562
|
+
}
|
|
8563
|
+
return Math.min(0.9, confidence);
|
|
8564
|
+
}
|
|
8565
|
+
function analyzeGitHistory(repoPath, options = {}) {
|
|
8566
|
+
const commits = getGitCommits(repoPath, options);
|
|
8567
|
+
const ignorePatterns = ["merge", "wip", "typo"];
|
|
8568
|
+
const patterns = [];
|
|
8569
|
+
const summary = {
|
|
8570
|
+
totalCommits: commits.length,
|
|
8571
|
+
totalFilesChanged: 0,
|
|
8572
|
+
errorFixes: 0,
|
|
8573
|
+
refactors: 0,
|
|
8574
|
+
features: 0,
|
|
8575
|
+
documentation: 0,
|
|
8576
|
+
tests: 0
|
|
8577
|
+
};
|
|
8578
|
+
const languages = /* @__PURE__ */ new Set();
|
|
8579
|
+
const frameworks = /* @__PURE__ */ new Set();
|
|
8580
|
+
for (const commit of commits) {
|
|
8581
|
+
if (shouldSkipCommit(commit, ignorePatterns)) {
|
|
8582
|
+
continue;
|
|
8583
|
+
}
|
|
8584
|
+
summary.totalFilesChanged += commit.files.length;
|
|
8585
|
+
for (const file of commit.files) {
|
|
8586
|
+
const ext = file.path.split(".").pop()?.toLowerCase();
|
|
8587
|
+
if (ext) {
|
|
8588
|
+
if (["ts", "tsx"].includes(ext)) languages.add("TypeScript");
|
|
8589
|
+
else if (["js", "jsx"].includes(ext)) languages.add("JavaScript");
|
|
8590
|
+
else if (ext === "py") languages.add("Python");
|
|
8591
|
+
else if (ext === "go") languages.add("Go");
|
|
8592
|
+
else if (ext === "rs") languages.add("Rust");
|
|
8593
|
+
else if (ext === "java") languages.add("Java");
|
|
8594
|
+
}
|
|
8595
|
+
if (file.path.includes("next")) frameworks.add("Next.js");
|
|
8596
|
+
if (file.path.includes("react")) frameworks.add("React");
|
|
8597
|
+
if (file.path.includes("vue")) frameworks.add("Vue");
|
|
8598
|
+
}
|
|
8599
|
+
const category = categorizeCommit(commit.message, commit.body);
|
|
8600
|
+
if (category === "error_fix") summary.errorFixes++;
|
|
8601
|
+
else if (category === "refactor") summary.refactors++;
|
|
8602
|
+
if (commit.message.toLowerCase().includes("feat")) summary.features++;
|
|
8603
|
+
if (commit.message.toLowerCase().includes("doc")) summary.documentation++;
|
|
8604
|
+
if (commit.message.toLowerCase().includes("test")) summary.tests++;
|
|
8605
|
+
const pattern = extractPatternFromCommit(commit);
|
|
8606
|
+
if (pattern) {
|
|
8607
|
+
patterns.push(pattern);
|
|
8608
|
+
}
|
|
8609
|
+
}
|
|
8610
|
+
const dates = commits.map((c) => c.date).sort();
|
|
8611
|
+
return {
|
|
8612
|
+
patterns,
|
|
8613
|
+
commitCount: commits.length,
|
|
8614
|
+
dateRange: {
|
|
8615
|
+
from: dates[0] || "",
|
|
8616
|
+
to: dates[dates.length - 1] || ""
|
|
8617
|
+
},
|
|
8618
|
+
languages: Array.from(languages),
|
|
8619
|
+
frameworks: Array.from(frameworks),
|
|
8620
|
+
summary
|
|
8621
|
+
};
|
|
8622
|
+
}
|
|
8623
|
+
function getRecentBugFixes(repoPath, limit = 20) {
|
|
8624
|
+
const result = analyzeGitHistory(repoPath, { commits: limit * 3 });
|
|
8625
|
+
return result.patterns.filter((p) => p.category === "error_fix").slice(0, limit);
|
|
8626
|
+
}
|
|
8627
|
+
function getRecentRefactors(repoPath, limit = 20) {
|
|
8628
|
+
const result = analyzeGitHistory(repoPath, { commits: limit * 3 });
|
|
8629
|
+
return result.patterns.filter((p) => p.category === "refactor").slice(0, limit);
|
|
8630
|
+
}
|
|
8631
|
+
|
|
8632
|
+
// src/session/session-explainer.ts
|
|
8633
|
+
function formatDuration(ms) {
|
|
8634
|
+
const seconds = Math.floor(ms / 1e3);
|
|
8635
|
+
const minutes = Math.floor(seconds / 60);
|
|
8636
|
+
const hours = Math.floor(minutes / 60);
|
|
8637
|
+
if (hours > 0) {
|
|
8638
|
+
const remainMinutes = minutes % 60;
|
|
8639
|
+
return `${hours}h ${remainMinutes}m`;
|
|
8640
|
+
}
|
|
8641
|
+
if (minutes > 0) {
|
|
8642
|
+
return `${minutes}m`;
|
|
8643
|
+
}
|
|
8644
|
+
return `${seconds}s`;
|
|
8645
|
+
}
|
|
8646
|
+
var SessionExplainer = class {
|
|
8647
|
+
projectPath;
|
|
8648
|
+
sessionManager;
|
|
8649
|
+
constructor(projectPath) {
|
|
8650
|
+
this.projectPath = projectPath;
|
|
8651
|
+
this.sessionManager = new SessionManager(projectPath);
|
|
8652
|
+
}
|
|
8653
|
+
explain(options) {
|
|
8654
|
+
const state = this.sessionManager.get();
|
|
8655
|
+
const includeGit = options?.includeGit !== false;
|
|
8656
|
+
const explanation = {
|
|
8657
|
+
date: (/* @__PURE__ */ new Date()).toISOString().split("T")[0],
|
|
8658
|
+
agent: "unknown",
|
|
8659
|
+
skillsUsed: [],
|
|
8660
|
+
tasks: [],
|
|
8661
|
+
filesModified: [],
|
|
8662
|
+
decisions: [],
|
|
8663
|
+
observationCounts: { errors: 0, solutions: 0, patterns: 0, total: 0 },
|
|
8664
|
+
gitCommits: 0
|
|
8665
|
+
};
|
|
8666
|
+
if (!state) {
|
|
8667
|
+
return explanation;
|
|
8668
|
+
}
|
|
8669
|
+
try {
|
|
8670
|
+
const configAgent = loadConfig().agent;
|
|
8671
|
+
if (configAgent && configAgent !== "universal") {
|
|
8672
|
+
explanation.agent = configAgent;
|
|
8673
|
+
} else if (state.currentExecution?.skillSource) {
|
|
8674
|
+
explanation.agent = state.currentExecution.skillSource;
|
|
8675
|
+
}
|
|
8676
|
+
} catch {
|
|
8677
|
+
if (state.currentExecution?.skillSource) {
|
|
8678
|
+
explanation.agent = state.currentExecution.skillSource;
|
|
8679
|
+
}
|
|
8680
|
+
}
|
|
8681
|
+
if (state.currentExecution) {
|
|
8682
|
+
const exec2 = state.currentExecution;
|
|
8683
|
+
const startTime = new Date(exec2.startedAt).getTime();
|
|
8684
|
+
explanation.duration = formatDuration(Date.now() - startTime);
|
|
8685
|
+
explanation.skillsUsed.push({
|
|
8686
|
+
name: exec2.skillName,
|
|
8687
|
+
status: exec2.status
|
|
8688
|
+
});
|
|
8689
|
+
for (const task of exec2.tasks) {
|
|
8690
|
+
const taskEntry = {
|
|
8691
|
+
name: task.name,
|
|
8692
|
+
status: task.status
|
|
8693
|
+
};
|
|
8694
|
+
if (task.startedAt && task.completedAt) {
|
|
8695
|
+
const dur = new Date(task.completedAt).getTime() - new Date(task.startedAt).getTime();
|
|
8696
|
+
taskEntry.duration = formatDuration(dur);
|
|
8697
|
+
}
|
|
8698
|
+
explanation.tasks.push(taskEntry);
|
|
8699
|
+
if (task.filesModified) {
|
|
8700
|
+
explanation.filesModified.push(...task.filesModified);
|
|
8701
|
+
}
|
|
8702
|
+
}
|
|
8703
|
+
}
|
|
8704
|
+
for (const hist of state.history ?? []) {
|
|
8705
|
+
const alreadyListed = explanation.skillsUsed.some(
|
|
8706
|
+
(s) => s.name === hist.skillName
|
|
8707
|
+
);
|
|
8708
|
+
if (!alreadyListed) {
|
|
8709
|
+
explanation.skillsUsed.push({
|
|
8710
|
+
name: hist.skillName,
|
|
8711
|
+
status: hist.status
|
|
8712
|
+
});
|
|
8713
|
+
}
|
|
8714
|
+
if (hist.filesModified) {
|
|
8715
|
+
explanation.filesModified.push(...hist.filesModified);
|
|
8716
|
+
}
|
|
8717
|
+
}
|
|
8718
|
+
explanation.filesModified = [...new Set(explanation.filesModified)];
|
|
8719
|
+
explanation.decisions = (state.decisions ?? []).map(({ key, value }) => ({ key, value }));
|
|
8720
|
+
try {
|
|
8721
|
+
const observations = ObservationStore.readAll(this.projectPath);
|
|
8722
|
+
const countByType = (type) => observations.filter((o) => o.type === type).length;
|
|
8723
|
+
explanation.observationCounts = {
|
|
8724
|
+
total: observations.length,
|
|
8725
|
+
errors: countByType("error"),
|
|
8726
|
+
solutions: countByType("solution"),
|
|
8727
|
+
patterns: countByType("pattern")
|
|
8728
|
+
};
|
|
8729
|
+
} catch {
|
|
8730
|
+
}
|
|
8731
|
+
if (includeGit) {
|
|
8732
|
+
try {
|
|
8733
|
+
const commits = getGitCommits(this.projectPath, { commits: 50 });
|
|
8734
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
8735
|
+
explanation.gitCommits = commits.filter(
|
|
8736
|
+
(c) => c.date.startsWith(today)
|
|
8737
|
+
).length;
|
|
8738
|
+
} catch {
|
|
8739
|
+
}
|
|
8740
|
+
}
|
|
8741
|
+
return explanation;
|
|
8742
|
+
}
|
|
8743
|
+
formatText(explanation) {
|
|
8744
|
+
const lines = [];
|
|
8745
|
+
lines.push(" Session Summary\n");
|
|
8746
|
+
if (explanation.duration) {
|
|
8747
|
+
lines.push(` Duration: ${explanation.duration}`);
|
|
8748
|
+
}
|
|
8749
|
+
lines.push(` Agent: ${explanation.agent}`);
|
|
8750
|
+
lines.push("");
|
|
8751
|
+
if (explanation.skillsUsed.length > 0) {
|
|
8752
|
+
lines.push(" Skills Used");
|
|
8753
|
+
for (const skill of explanation.skillsUsed) {
|
|
8754
|
+
const icon = skill.status === "completed" ? "\u2713" : "\u25CB";
|
|
8755
|
+
lines.push(` ${icon} ${skill.name} (${skill.status})`);
|
|
8756
|
+
}
|
|
8757
|
+
lines.push("");
|
|
8758
|
+
}
|
|
8759
|
+
if (explanation.tasks.length > 0) {
|
|
8760
|
+
lines.push(` Tasks (${explanation.tasks.length} total)`);
|
|
8761
|
+
for (const task of explanation.tasks) {
|
|
8762
|
+
const icon = task.status === "completed" ? "\u2713" : "\u25CB";
|
|
8763
|
+
const dur = task.duration ? ` (${task.duration})` : "";
|
|
8764
|
+
lines.push(` ${icon} ${task.name}${dur}`);
|
|
8765
|
+
}
|
|
8766
|
+
lines.push("");
|
|
8767
|
+
}
|
|
8768
|
+
lines.push(` Files Modified: ${explanation.filesModified.length} files`);
|
|
8769
|
+
lines.push(` Git Commits: ${explanation.gitCommits}`);
|
|
8770
|
+
lines.push("");
|
|
8771
|
+
if (explanation.decisions.length > 0) {
|
|
8772
|
+
lines.push(" Decisions");
|
|
8773
|
+
for (const d of explanation.decisions) {
|
|
8774
|
+
lines.push(` ${d.key} \u2192 ${d.value}`);
|
|
8775
|
+
}
|
|
8776
|
+
lines.push("");
|
|
8777
|
+
}
|
|
8778
|
+
const obs = explanation.observationCounts;
|
|
8779
|
+
lines.push(
|
|
8780
|
+
` Observations: ${obs.errors} errors, ${obs.solutions} solutions, ${obs.patterns} patterns`
|
|
8781
|
+
);
|
|
8782
|
+
return lines.join("\n");
|
|
8783
|
+
}
|
|
8784
|
+
formatJson(explanation) {
|
|
8785
|
+
return JSON.stringify(explanation, null, 2);
|
|
8786
|
+
}
|
|
8787
|
+
};
|
|
8788
|
+
|
|
7958
8789
|
// src/workflow/types.ts
|
|
7959
8790
|
var WORKFLOWS_DIR = "workflows";
|
|
7960
8791
|
var WORKFLOW_EXTENSION = ".yaml";
|
|
@@ -8017,11 +8848,11 @@ function getBuiltinPipelines() {
|
|
|
8017
8848
|
}
|
|
8018
8849
|
|
|
8019
8850
|
// src/workflow/parser.ts
|
|
8020
|
-
import { existsSync as
|
|
8021
|
-
import { join as
|
|
8022
|
-
import { parse as
|
|
8851
|
+
import { existsSync as existsSync22, readFileSync as readFileSync13, readdirSync as readdirSync6, writeFileSync as writeFileSync12, mkdirSync as mkdirSync12 } from "fs";
|
|
8852
|
+
import { join as join21 } from "path";
|
|
8853
|
+
import { parse as parse4, stringify as stringify4 } from "yaml";
|
|
8023
8854
|
function parseWorkflow(content) {
|
|
8024
|
-
const data =
|
|
8855
|
+
const data = parse4(content);
|
|
8025
8856
|
if (!data.name || typeof data.name !== "string") {
|
|
8026
8857
|
throw new Error("Workflow must have a name");
|
|
8027
8858
|
}
|
|
@@ -8070,25 +8901,25 @@ function parseWorkflow(content) {
|
|
|
8070
8901
|
};
|
|
8071
8902
|
}
|
|
8072
8903
|
function loadWorkflow(filePath) {
|
|
8073
|
-
if (!
|
|
8904
|
+
if (!existsSync22(filePath)) {
|
|
8074
8905
|
throw new Error(`Workflow file not found: ${filePath}`);
|
|
8075
8906
|
}
|
|
8076
|
-
const content =
|
|
8907
|
+
const content = readFileSync13(filePath, "utf-8");
|
|
8077
8908
|
return parseWorkflow(content);
|
|
8078
8909
|
}
|
|
8079
8910
|
function loadWorkflowByName(projectPath, name) {
|
|
8080
|
-
const workflowsDir =
|
|
8081
|
-
if (!
|
|
8911
|
+
const workflowsDir = join21(projectPath, ".skillkit", WORKFLOWS_DIR);
|
|
8912
|
+
if (!existsSync22(workflowsDir)) {
|
|
8082
8913
|
return null;
|
|
8083
8914
|
}
|
|
8084
|
-
const exactPath =
|
|
8085
|
-
if (
|
|
8915
|
+
const exactPath = join21(workflowsDir, `${name}${WORKFLOW_EXTENSION}`);
|
|
8916
|
+
if (existsSync22(exactPath)) {
|
|
8086
8917
|
return loadWorkflow(exactPath);
|
|
8087
8918
|
}
|
|
8088
|
-
const files =
|
|
8919
|
+
const files = readdirSync6(workflowsDir).filter((f) => f.endsWith(WORKFLOW_EXTENSION));
|
|
8089
8920
|
for (const file of files) {
|
|
8090
8921
|
try {
|
|
8091
|
-
const workflow = loadWorkflow(
|
|
8922
|
+
const workflow = loadWorkflow(join21(workflowsDir, file));
|
|
8092
8923
|
if (workflow.name === name) {
|
|
8093
8924
|
return workflow;
|
|
8094
8925
|
}
|
|
@@ -8098,15 +8929,15 @@ function loadWorkflowByName(projectPath, name) {
|
|
|
8098
8929
|
return null;
|
|
8099
8930
|
}
|
|
8100
8931
|
function listWorkflows(projectPath) {
|
|
8101
|
-
const workflowsDir =
|
|
8102
|
-
if (!
|
|
8932
|
+
const workflowsDir = join21(projectPath, ".skillkit", WORKFLOWS_DIR);
|
|
8933
|
+
if (!existsSync22(workflowsDir)) {
|
|
8103
8934
|
return [];
|
|
8104
8935
|
}
|
|
8105
|
-
const files =
|
|
8936
|
+
const files = readdirSync6(workflowsDir).filter((f) => f.endsWith(WORKFLOW_EXTENSION));
|
|
8106
8937
|
const workflows = [];
|
|
8107
8938
|
for (const file of files) {
|
|
8108
8939
|
try {
|
|
8109
|
-
const workflow = loadWorkflow(
|
|
8940
|
+
const workflow = loadWorkflow(join21(workflowsDir, file));
|
|
8110
8941
|
workflows.push(workflow);
|
|
8111
8942
|
} catch {
|
|
8112
8943
|
}
|
|
@@ -8114,17 +8945,17 @@ function listWorkflows(projectPath) {
|
|
|
8114
8945
|
return workflows;
|
|
8115
8946
|
}
|
|
8116
8947
|
function saveWorkflow(projectPath, workflow) {
|
|
8117
|
-
const workflowsDir =
|
|
8118
|
-
if (!
|
|
8119
|
-
|
|
8948
|
+
const workflowsDir = join21(projectPath, ".skillkit", WORKFLOWS_DIR);
|
|
8949
|
+
if (!existsSync22(workflowsDir)) {
|
|
8950
|
+
mkdirSync12(workflowsDir, { recursive: true });
|
|
8120
8951
|
}
|
|
8121
8952
|
const fileName = `${workflow.name.replace(/[^a-z0-9-]/gi, "-").toLowerCase()}${WORKFLOW_EXTENSION}`;
|
|
8122
|
-
const filePath =
|
|
8123
|
-
|
|
8953
|
+
const filePath = join21(workflowsDir, fileName);
|
|
8954
|
+
writeFileSync12(filePath, stringify4(workflow));
|
|
8124
8955
|
return filePath;
|
|
8125
8956
|
}
|
|
8126
8957
|
function serializeWorkflow(workflow) {
|
|
8127
|
-
return
|
|
8958
|
+
return stringify4(workflow);
|
|
8128
8959
|
}
|
|
8129
8960
|
function validateWorkflow(workflow) {
|
|
8130
8961
|
const errors = [];
|
|
@@ -8173,7 +9004,7 @@ function createWorkflowTemplate(name, description) {
|
|
|
8173
9004
|
}
|
|
8174
9005
|
|
|
8175
9006
|
// src/workflow/orchestrator.ts
|
|
8176
|
-
import { randomUUID as
|
|
9007
|
+
import { randomUUID as randomUUID7 } from "crypto";
|
|
8177
9008
|
var WorkflowOrchestrator = class {
|
|
8178
9009
|
execution = null;
|
|
8179
9010
|
executor;
|
|
@@ -8194,7 +9025,7 @@ var WorkflowOrchestrator = class {
|
|
|
8194
9025
|
async execute(workflow) {
|
|
8195
9026
|
this.execution = {
|
|
8196
9027
|
workflow,
|
|
8197
|
-
executionId:
|
|
9028
|
+
executionId: randomUUID7(),
|
|
8198
9029
|
status: "running",
|
|
8199
9030
|
currentWave: 0,
|
|
8200
9031
|
waves: workflow.waves.map((wave, index) => ({
|
|
@@ -8386,8 +9217,8 @@ function createWorkflowOrchestrator(executor, onProgress) {
|
|
|
8386
9217
|
}
|
|
8387
9218
|
|
|
8388
9219
|
// src/executor/engine.ts
|
|
8389
|
-
import { execSync as
|
|
8390
|
-
import { randomUUID as
|
|
9220
|
+
import { execSync as execSync6 } from "child_process";
|
|
9221
|
+
import { randomUUID as randomUUID8 } from "crypto";
|
|
8391
9222
|
var SkillExecutionEngine = class {
|
|
8392
9223
|
projectPath;
|
|
8393
9224
|
sessionManager;
|
|
@@ -8612,7 +9443,7 @@ var SkillExecutionEngine = class {
|
|
|
8612
9443
|
*/
|
|
8613
9444
|
async executeTask(task, _skill, _options) {
|
|
8614
9445
|
const startTime = /* @__PURE__ */ new Date();
|
|
8615
|
-
const taskId = task.id ||
|
|
9446
|
+
const taskId = task.id || randomUUID8();
|
|
8616
9447
|
try {
|
|
8617
9448
|
await new Promise((resolve6) => setTimeout(resolve6, 100));
|
|
8618
9449
|
const endTime = /* @__PURE__ */ new Date();
|
|
@@ -8726,7 +9557,7 @@ var SkillExecutionEngine = class {
|
|
|
8726
9557
|
for (const rule of task.verify.automated) {
|
|
8727
9558
|
if (rule.command) {
|
|
8728
9559
|
try {
|
|
8729
|
-
const output =
|
|
9560
|
+
const output = execSync6(rule.command, {
|
|
8730
9561
|
cwd: this.projectPath,
|
|
8731
9562
|
encoding: "utf-8",
|
|
8732
9563
|
timeout: 3e4
|
|
@@ -8784,7 +9615,7 @@ var SkillExecutionEngine = class {
|
|
|
8784
9615
|
completedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8785
9616
|
durationMs: 0,
|
|
8786
9617
|
tasks: tasks.map((task) => ({
|
|
8787
|
-
taskId: task.id ||
|
|
9618
|
+
taskId: task.id || randomUUID8(),
|
|
8788
9619
|
taskName: task.name,
|
|
8789
9620
|
status: "skipped",
|
|
8790
9621
|
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -9040,26 +9871,26 @@ To execute this skill manually:
|
|
|
9040
9871
|
}
|
|
9041
9872
|
|
|
9042
9873
|
// src/executor/skill-executor.ts
|
|
9043
|
-
import { existsSync as
|
|
9044
|
-
import { join as
|
|
9874
|
+
import { existsSync as existsSync23 } from "fs";
|
|
9875
|
+
import { join as join22 } from "path";
|
|
9045
9876
|
import { homedir as homedir7 } from "os";
|
|
9046
9877
|
function getSearchDirs2(projectPath) {
|
|
9047
9878
|
const dirs = [];
|
|
9048
9879
|
for (const searchPath of SKILL_DISCOVERY_PATHS) {
|
|
9049
|
-
const fullPath =
|
|
9050
|
-
if (
|
|
9880
|
+
const fullPath = join22(projectPath, searchPath);
|
|
9881
|
+
if (existsSync23(fullPath)) {
|
|
9051
9882
|
dirs.push(fullPath);
|
|
9052
9883
|
}
|
|
9053
9884
|
}
|
|
9054
9885
|
const home = homedir7();
|
|
9055
9886
|
const globalPaths = [
|
|
9056
|
-
|
|
9057
|
-
|
|
9058
|
-
|
|
9059
|
-
|
|
9887
|
+
join22(home, ".claude", "skills"),
|
|
9888
|
+
join22(home, ".cursor", "skills"),
|
|
9889
|
+
join22(home, ".codex", "skills"),
|
|
9890
|
+
join22(home, ".skillkit", "skills")
|
|
9060
9891
|
];
|
|
9061
9892
|
for (const globalPath of globalPaths) {
|
|
9062
|
-
if (
|
|
9893
|
+
if (existsSync23(globalPath)) {
|
|
9063
9894
|
dirs.push(globalPath);
|
|
9064
9895
|
}
|
|
9065
9896
|
}
|
|
@@ -9189,12 +10020,12 @@ function createSimulatedSkillExecutor(options = {}) {
|
|
|
9189
10020
|
}
|
|
9190
10021
|
|
|
9191
10022
|
// src/testing/runner.ts
|
|
9192
|
-
import { existsSync as
|
|
9193
|
-
import { join as
|
|
10023
|
+
import { existsSync as existsSync24, readFileSync as readFileSync14 } from "fs";
|
|
10024
|
+
import { join as join23 } from "path";
|
|
9194
10025
|
import { exec } from "child_process";
|
|
9195
10026
|
import { createServer } from "net";
|
|
9196
10027
|
import { promisify } from "util";
|
|
9197
|
-
import { parse as
|
|
10028
|
+
import { parse as parseYaml7 } from "yaml";
|
|
9198
10029
|
var execAsync = promisify(exec);
|
|
9199
10030
|
var DEFAULT_TIMEOUT = 3e4;
|
|
9200
10031
|
async function runAssertion(assertion, cwd, timeout) {
|
|
@@ -9255,8 +10086,8 @@ async function runAssertion(assertion, cwd, timeout) {
|
|
|
9255
10086
|
}
|
|
9256
10087
|
}
|
|
9257
10088
|
function assertFileExists(assertion, cwd, startTime) {
|
|
9258
|
-
const filePath =
|
|
9259
|
-
const exists =
|
|
10089
|
+
const filePath = join23(cwd, assertion.target || "");
|
|
10090
|
+
const exists = existsSync24(filePath);
|
|
9260
10091
|
return {
|
|
9261
10092
|
assertion,
|
|
9262
10093
|
passed: exists,
|
|
@@ -9267,8 +10098,8 @@ function assertFileExists(assertion, cwd, startTime) {
|
|
|
9267
10098
|
};
|
|
9268
10099
|
}
|
|
9269
10100
|
function assertFileNotExists(assertion, cwd, startTime) {
|
|
9270
|
-
const filePath =
|
|
9271
|
-
const exists =
|
|
10101
|
+
const filePath = join23(cwd, assertion.target || "");
|
|
10102
|
+
const exists = existsSync24(filePath);
|
|
9272
10103
|
return {
|
|
9273
10104
|
assertion,
|
|
9274
10105
|
passed: !exists,
|
|
@@ -9279,8 +10110,8 @@ function assertFileNotExists(assertion, cwd, startTime) {
|
|
|
9279
10110
|
};
|
|
9280
10111
|
}
|
|
9281
10112
|
function assertFileContains(assertion, cwd, startTime) {
|
|
9282
|
-
const filePath =
|
|
9283
|
-
if (!
|
|
10113
|
+
const filePath = join23(cwd, assertion.target || "");
|
|
10114
|
+
if (!existsSync24(filePath)) {
|
|
9284
10115
|
return {
|
|
9285
10116
|
assertion,
|
|
9286
10117
|
passed: false,
|
|
@@ -9288,7 +10119,7 @@ function assertFileContains(assertion, cwd, startTime) {
|
|
|
9288
10119
|
duration: Date.now() - startTime
|
|
9289
10120
|
};
|
|
9290
10121
|
}
|
|
9291
|
-
const content =
|
|
10122
|
+
const content = readFileSync14(filePath, "utf-8");
|
|
9292
10123
|
const expected = String(assertion.expected || "");
|
|
9293
10124
|
const contains = content.includes(expected);
|
|
9294
10125
|
return {
|
|
@@ -9301,8 +10132,8 @@ function assertFileContains(assertion, cwd, startTime) {
|
|
|
9301
10132
|
};
|
|
9302
10133
|
}
|
|
9303
10134
|
function assertFileNotContains(assertion, cwd, startTime) {
|
|
9304
|
-
const filePath =
|
|
9305
|
-
if (!
|
|
10135
|
+
const filePath = join23(cwd, assertion.target || "");
|
|
10136
|
+
if (!existsSync24(filePath)) {
|
|
9306
10137
|
return {
|
|
9307
10138
|
assertion,
|
|
9308
10139
|
passed: true,
|
|
@@ -9310,7 +10141,7 @@ function assertFileNotContains(assertion, cwd, startTime) {
|
|
|
9310
10141
|
duration: Date.now() - startTime
|
|
9311
10142
|
};
|
|
9312
10143
|
}
|
|
9313
|
-
const content =
|
|
10144
|
+
const content = readFileSync14(filePath, "utf-8");
|
|
9314
10145
|
const expected = String(assertion.expected || "");
|
|
9315
10146
|
const contains = content.includes(expected);
|
|
9316
10147
|
return {
|
|
@@ -9323,8 +10154,8 @@ function assertFileNotContains(assertion, cwd, startTime) {
|
|
|
9323
10154
|
};
|
|
9324
10155
|
}
|
|
9325
10156
|
function assertFileMatches(assertion, cwd, startTime) {
|
|
9326
|
-
const filePath =
|
|
9327
|
-
if (!
|
|
10157
|
+
const filePath = join23(cwd, assertion.target || "");
|
|
10158
|
+
if (!existsSync24(filePath)) {
|
|
9328
10159
|
return {
|
|
9329
10160
|
assertion,
|
|
9330
10161
|
passed: false,
|
|
@@ -9332,7 +10163,7 @@ function assertFileMatches(assertion, cwd, startTime) {
|
|
|
9332
10163
|
duration: Date.now() - startTime
|
|
9333
10164
|
};
|
|
9334
10165
|
}
|
|
9335
|
-
const content =
|
|
10166
|
+
const content = readFileSync14(filePath, "utf-8");
|
|
9336
10167
|
const pattern = new RegExp(String(assertion.expected || ""));
|
|
9337
10168
|
const matches = pattern.test(content);
|
|
9338
10169
|
return {
|
|
@@ -9419,8 +10250,8 @@ async function assertCommandOutputContains(assertion, cwd, timeout, startTime) {
|
|
|
9419
10250
|
}
|
|
9420
10251
|
}
|
|
9421
10252
|
function assertJsonValid(assertion, cwd, startTime) {
|
|
9422
|
-
const filePath =
|
|
9423
|
-
if (!
|
|
10253
|
+
const filePath = join23(cwd, assertion.target || "");
|
|
10254
|
+
if (!existsSync24(filePath)) {
|
|
9424
10255
|
return {
|
|
9425
10256
|
assertion,
|
|
9426
10257
|
passed: false,
|
|
@@ -9429,7 +10260,7 @@ function assertJsonValid(assertion, cwd, startTime) {
|
|
|
9429
10260
|
};
|
|
9430
10261
|
}
|
|
9431
10262
|
try {
|
|
9432
|
-
const content =
|
|
10263
|
+
const content = readFileSync14(filePath, "utf-8");
|
|
9433
10264
|
JSON.parse(content);
|
|
9434
10265
|
return {
|
|
9435
10266
|
assertion,
|
|
@@ -9450,8 +10281,8 @@ function assertJsonValid(assertion, cwd, startTime) {
|
|
|
9450
10281
|
}
|
|
9451
10282
|
}
|
|
9452
10283
|
function assertJsonHasKey(assertion, cwd, startTime) {
|
|
9453
|
-
const filePath =
|
|
9454
|
-
if (!
|
|
10284
|
+
const filePath = join23(cwd, assertion.target || "");
|
|
10285
|
+
if (!existsSync24(filePath)) {
|
|
9455
10286
|
return {
|
|
9456
10287
|
assertion,
|
|
9457
10288
|
passed: false,
|
|
@@ -9460,7 +10291,7 @@ function assertJsonHasKey(assertion, cwd, startTime) {
|
|
|
9460
10291
|
};
|
|
9461
10292
|
}
|
|
9462
10293
|
try {
|
|
9463
|
-
const content =
|
|
10294
|
+
const content = readFileSync14(filePath, "utf-8");
|
|
9464
10295
|
const json = JSON.parse(content);
|
|
9465
10296
|
const key = String(assertion.expected || "");
|
|
9466
10297
|
const keys = key.split(".");
|
|
@@ -9495,8 +10326,8 @@ function assertJsonHasKey(assertion, cwd, startTime) {
|
|
|
9495
10326
|
}
|
|
9496
10327
|
}
|
|
9497
10328
|
function assertYamlValid(assertion, cwd, startTime) {
|
|
9498
|
-
const filePath =
|
|
9499
|
-
if (!
|
|
10329
|
+
const filePath = join23(cwd, assertion.target || "");
|
|
10330
|
+
if (!existsSync24(filePath)) {
|
|
9500
10331
|
return {
|
|
9501
10332
|
assertion,
|
|
9502
10333
|
passed: false,
|
|
@@ -9505,8 +10336,8 @@ function assertYamlValid(assertion, cwd, startTime) {
|
|
|
9505
10336
|
};
|
|
9506
10337
|
}
|
|
9507
10338
|
try {
|
|
9508
|
-
const content =
|
|
9509
|
-
|
|
10339
|
+
const content = readFileSync14(filePath, "utf-8");
|
|
10340
|
+
parseYaml7(content);
|
|
9510
10341
|
return {
|
|
9511
10342
|
assertion,
|
|
9512
10343
|
passed: true,
|
|
@@ -10028,8 +10859,8 @@ var MARKETPLACE_CACHE_FILE = "marketplace-index.json";
|
|
|
10028
10859
|
var DEFAULT_CACHE_TTL = 60 * 60 * 1e3;
|
|
10029
10860
|
|
|
10030
10861
|
// src/marketplace/aggregator.ts
|
|
10031
|
-
import { existsSync as
|
|
10032
|
-
import { join as
|
|
10862
|
+
import { existsSync as existsSync25, readFileSync as readFileSync15, writeFileSync as writeFileSync13, mkdirSync as mkdirSync13, unlinkSync as unlinkSync3 } from "fs";
|
|
10863
|
+
import { join as join24 } from "path";
|
|
10033
10864
|
import { homedir as homedir8 } from "os";
|
|
10034
10865
|
var MarketplaceAggregator = class {
|
|
10035
10866
|
config;
|
|
@@ -10038,10 +10869,10 @@ var MarketplaceAggregator = class {
|
|
|
10038
10869
|
index = null;
|
|
10039
10870
|
constructor(config = {}) {
|
|
10040
10871
|
this.config = config;
|
|
10041
|
-
this.cacheDir = config.cacheDir ||
|
|
10042
|
-
this.cachePath =
|
|
10043
|
-
if (!
|
|
10044
|
-
|
|
10872
|
+
this.cacheDir = config.cacheDir || join24(homedir8(), ".skillkit", "marketplace");
|
|
10873
|
+
this.cachePath = join24(this.cacheDir, MARKETPLACE_CACHE_FILE);
|
|
10874
|
+
if (!existsSync25(this.cacheDir)) {
|
|
10875
|
+
mkdirSync13(this.cacheDir, { recursive: true });
|
|
10045
10876
|
}
|
|
10046
10877
|
}
|
|
10047
10878
|
/**
|
|
@@ -10054,11 +10885,11 @@ var MarketplaceAggregator = class {
|
|
|
10054
10885
|
* Load cached index
|
|
10055
10886
|
*/
|
|
10056
10887
|
loadCache() {
|
|
10057
|
-
if (!
|
|
10888
|
+
if (!existsSync25(this.cachePath)) {
|
|
10058
10889
|
return null;
|
|
10059
10890
|
}
|
|
10060
10891
|
try {
|
|
10061
|
-
const content =
|
|
10892
|
+
const content = readFileSync15(this.cachePath, "utf-8");
|
|
10062
10893
|
const index = JSON.parse(content);
|
|
10063
10894
|
const cacheAge = Date.now() - new Date(index.updatedAt).getTime();
|
|
10064
10895
|
const ttl = this.config.cacheTTL || DEFAULT_CACHE_TTL;
|
|
@@ -10075,7 +10906,7 @@ var MarketplaceAggregator = class {
|
|
|
10075
10906
|
* Save index to cache
|
|
10076
10907
|
*/
|
|
10077
10908
|
saveCache(index) {
|
|
10078
|
-
|
|
10909
|
+
writeFileSync13(this.cachePath, JSON.stringify(index, null, 2));
|
|
10079
10910
|
this.index = index;
|
|
10080
10911
|
}
|
|
10081
10912
|
/**
|
|
@@ -10399,8 +11230,8 @@ var MarketplaceAggregator = class {
|
|
|
10399
11230
|
* Clear cache
|
|
10400
11231
|
*/
|
|
10401
11232
|
clearCache() {
|
|
10402
|
-
if (
|
|
10403
|
-
|
|
11233
|
+
if (existsSync25(this.cachePath)) {
|
|
11234
|
+
unlinkSync3(this.cachePath);
|
|
10404
11235
|
}
|
|
10405
11236
|
this.index = null;
|
|
10406
11237
|
}
|
|
@@ -10624,203 +11455,9 @@ var DEFAULT_MEMORY_CONFIG = {
|
|
|
10624
11455
|
maxLearnings: 500
|
|
10625
11456
|
};
|
|
10626
11457
|
|
|
10627
|
-
// src/memory/observation-store.ts
|
|
10628
|
-
import { existsSync as existsSync22, mkdirSync as mkdirSync11, readFileSync as readFileSync13, writeFileSync as writeFileSync11 } from "fs";
|
|
10629
|
-
import { dirname as dirname4, join as join21 } from "path";
|
|
10630
|
-
import { parse as parseYaml7, stringify as stringifyYaml5 } from "yaml";
|
|
10631
|
-
import { randomUUID as randomUUID8 } from "crypto";
|
|
10632
|
-
var ObservationStore = class {
|
|
10633
|
-
filePath;
|
|
10634
|
-
projectPath;
|
|
10635
|
-
data = null;
|
|
10636
|
-
sessionId;
|
|
10637
|
-
compressionThreshold;
|
|
10638
|
-
autoCompress;
|
|
10639
|
-
onThresholdReached;
|
|
10640
|
-
compressionInProgress = false;
|
|
10641
|
-
constructor(projectPath, sessionId, options = {}) {
|
|
10642
|
-
this.projectPath = projectPath;
|
|
10643
|
-
this.filePath = join21(projectPath, ".skillkit", "memory", "observations.yaml");
|
|
10644
|
-
this.sessionId = sessionId || randomUUID8();
|
|
10645
|
-
this.compressionThreshold = options.compressionThreshold ?? 50;
|
|
10646
|
-
this.autoCompress = options.autoCompress ?? true;
|
|
10647
|
-
this.onThresholdReached = options.onThresholdReached;
|
|
10648
|
-
}
|
|
10649
|
-
ensureDir() {
|
|
10650
|
-
const dir = dirname4(this.filePath);
|
|
10651
|
-
if (!existsSync22(dir)) {
|
|
10652
|
-
mkdirSync11(dir, { recursive: true });
|
|
10653
|
-
}
|
|
10654
|
-
}
|
|
10655
|
-
load() {
|
|
10656
|
-
if (this.data) return this.data;
|
|
10657
|
-
if (existsSync22(this.filePath)) {
|
|
10658
|
-
try {
|
|
10659
|
-
const content = readFileSync13(this.filePath, "utf-8");
|
|
10660
|
-
this.data = parseYaml7(content);
|
|
10661
|
-
if (this.data.sessionId !== this.sessionId) {
|
|
10662
|
-
this.data.sessionId = this.sessionId;
|
|
10663
|
-
this.data.observations = [];
|
|
10664
|
-
}
|
|
10665
|
-
} catch {
|
|
10666
|
-
this.data = this.createEmpty();
|
|
10667
|
-
}
|
|
10668
|
-
} else {
|
|
10669
|
-
this.data = this.createEmpty();
|
|
10670
|
-
}
|
|
10671
|
-
return this.data;
|
|
10672
|
-
}
|
|
10673
|
-
createEmpty() {
|
|
10674
|
-
return {
|
|
10675
|
-
version: 1,
|
|
10676
|
-
sessionId: this.sessionId,
|
|
10677
|
-
observations: []
|
|
10678
|
-
};
|
|
10679
|
-
}
|
|
10680
|
-
save() {
|
|
10681
|
-
this.ensureDir();
|
|
10682
|
-
const content = stringifyYaml5(this.data, { lineWidth: 0 });
|
|
10683
|
-
writeFileSync11(this.filePath, content, "utf-8");
|
|
10684
|
-
}
|
|
10685
|
-
add(type, content, agent, relevance = 50) {
|
|
10686
|
-
const data = this.load();
|
|
10687
|
-
const observation = {
|
|
10688
|
-
id: randomUUID8(),
|
|
10689
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
10690
|
-
sessionId: this.sessionId,
|
|
10691
|
-
agent,
|
|
10692
|
-
type,
|
|
10693
|
-
content,
|
|
10694
|
-
relevance
|
|
10695
|
-
};
|
|
10696
|
-
data.observations.push(observation);
|
|
10697
|
-
this.save();
|
|
10698
|
-
void this.checkAutoCompression().catch(() => {
|
|
10699
|
-
});
|
|
10700
|
-
return observation;
|
|
10701
|
-
}
|
|
10702
|
-
/**
|
|
10703
|
-
* Check if auto-compression should trigger
|
|
10704
|
-
*/
|
|
10705
|
-
async checkAutoCompression() {
|
|
10706
|
-
if (!this.autoCompress || this.compressionInProgress) return;
|
|
10707
|
-
if (!this.onThresholdReached) return;
|
|
10708
|
-
const count = this.count();
|
|
10709
|
-
if (count >= this.compressionThreshold) {
|
|
10710
|
-
this.compressionInProgress = true;
|
|
10711
|
-
try {
|
|
10712
|
-
const observations = this.getAll();
|
|
10713
|
-
await this.onThresholdReached(observations);
|
|
10714
|
-
} finally {
|
|
10715
|
-
this.compressionInProgress = false;
|
|
10716
|
-
}
|
|
10717
|
-
}
|
|
10718
|
-
}
|
|
10719
|
-
/**
|
|
10720
|
-
* Set auto-compression callback
|
|
10721
|
-
*/
|
|
10722
|
-
setAutoCompressCallback(callback) {
|
|
10723
|
-
this.onThresholdReached = callback;
|
|
10724
|
-
}
|
|
10725
|
-
/**
|
|
10726
|
-
* Enable/disable auto-compression
|
|
10727
|
-
*/
|
|
10728
|
-
setAutoCompress(enabled) {
|
|
10729
|
-
this.autoCompress = enabled;
|
|
10730
|
-
}
|
|
10731
|
-
/**
|
|
10732
|
-
* Set compression threshold
|
|
10733
|
-
*/
|
|
10734
|
-
setCompressionThreshold(threshold) {
|
|
10735
|
-
if (threshold < 1 || !Number.isInteger(threshold)) {
|
|
10736
|
-
throw new Error("Compression threshold must be a positive integer");
|
|
10737
|
-
}
|
|
10738
|
-
this.compressionThreshold = threshold;
|
|
10739
|
-
}
|
|
10740
|
-
/**
|
|
10741
|
-
* Get compression threshold
|
|
10742
|
-
*/
|
|
10743
|
-
getCompressionThreshold() {
|
|
10744
|
-
return this.compressionThreshold;
|
|
10745
|
-
}
|
|
10746
|
-
/**
|
|
10747
|
-
* Check if threshold is reached
|
|
10748
|
-
*/
|
|
10749
|
-
isThresholdReached() {
|
|
10750
|
-
return this.count() >= this.compressionThreshold;
|
|
10751
|
-
}
|
|
10752
|
-
/**
|
|
10753
|
-
* Get project path
|
|
10754
|
-
*/
|
|
10755
|
-
getProjectPath() {
|
|
10756
|
-
return this.projectPath;
|
|
10757
|
-
}
|
|
10758
|
-
getAll() {
|
|
10759
|
-
return this.load().observations;
|
|
10760
|
-
}
|
|
10761
|
-
getByType(type) {
|
|
10762
|
-
return this.load().observations.filter((o) => o.type === type);
|
|
10763
|
-
}
|
|
10764
|
-
getByRelevance(minRelevance) {
|
|
10765
|
-
return this.load().observations.filter((o) => o.relevance >= minRelevance);
|
|
10766
|
-
}
|
|
10767
|
-
getRecent(count) {
|
|
10768
|
-
const observations = this.load().observations;
|
|
10769
|
-
return observations.slice(-count);
|
|
10770
|
-
}
|
|
10771
|
-
getUncompressed(compressedIds) {
|
|
10772
|
-
const compressedSet = new Set(compressedIds);
|
|
10773
|
-
return this.load().observations.filter((o) => !compressedSet.has(o.id));
|
|
10774
|
-
}
|
|
10775
|
-
count() {
|
|
10776
|
-
return this.load().observations.length;
|
|
10777
|
-
}
|
|
10778
|
-
clear() {
|
|
10779
|
-
this.data = this.createEmpty();
|
|
10780
|
-
this.save();
|
|
10781
|
-
}
|
|
10782
|
-
getById(id) {
|
|
10783
|
-
return this.load().observations.find((o) => o.id === id);
|
|
10784
|
-
}
|
|
10785
|
-
getByIds(ids) {
|
|
10786
|
-
const idSet = new Set(ids);
|
|
10787
|
-
return this.load().observations.filter((o) => idSet.has(o.id));
|
|
10788
|
-
}
|
|
10789
|
-
getSessionId() {
|
|
10790
|
-
return this.sessionId;
|
|
10791
|
-
}
|
|
10792
|
-
setSessionId(sessionId) {
|
|
10793
|
-
this.sessionId = sessionId;
|
|
10794
|
-
if (this.data) {
|
|
10795
|
-
this.data.sessionId = sessionId;
|
|
10796
|
-
}
|
|
10797
|
-
}
|
|
10798
|
-
exists() {
|
|
10799
|
-
return existsSync22(this.filePath);
|
|
10800
|
-
}
|
|
10801
|
-
delete(id) {
|
|
10802
|
-
const data = this.load();
|
|
10803
|
-
const index = data.observations.findIndex((o) => o.id === id);
|
|
10804
|
-
if (index === -1) return false;
|
|
10805
|
-
data.observations.splice(index, 1);
|
|
10806
|
-
this.save();
|
|
10807
|
-
return true;
|
|
10808
|
-
}
|
|
10809
|
-
deleteMany(ids) {
|
|
10810
|
-
const idSet = new Set(ids);
|
|
10811
|
-
const data = this.load();
|
|
10812
|
-
const initialLength = data.observations.length;
|
|
10813
|
-
data.observations = data.observations.filter((o) => !idSet.has(o.id));
|
|
10814
|
-
if (data.observations.length !== initialLength) {
|
|
10815
|
-
this.save();
|
|
10816
|
-
}
|
|
10817
|
-
return initialLength - data.observations.length;
|
|
10818
|
-
}
|
|
10819
|
-
};
|
|
10820
|
-
|
|
10821
11458
|
// src/memory/learning-store.ts
|
|
10822
|
-
import { existsSync as
|
|
10823
|
-
import { dirname as dirname5, join as
|
|
11459
|
+
import { existsSync as existsSync26, mkdirSync as mkdirSync14, readFileSync as readFileSync16, writeFileSync as writeFileSync14 } from "fs";
|
|
11460
|
+
import { dirname as dirname5, join as join25 } from "path";
|
|
10824
11461
|
import { homedir as homedir9 } from "os";
|
|
10825
11462
|
import { parse as parseYaml8, stringify as stringifyYaml6 } from "yaml";
|
|
10826
11463
|
import { randomUUID as randomUUID9 } from "crypto";
|
|
@@ -10833,22 +11470,22 @@ var LearningStore = class {
|
|
|
10833
11470
|
this.scope = scope;
|
|
10834
11471
|
this.projectName = projectName;
|
|
10835
11472
|
if (scope === "project" && projectPath) {
|
|
10836
|
-
this.filePath =
|
|
11473
|
+
this.filePath = join25(projectPath, ".skillkit", "memory", "learnings.yaml");
|
|
10837
11474
|
} else {
|
|
10838
|
-
this.filePath =
|
|
11475
|
+
this.filePath = join25(homedir9(), ".skillkit", "memory", "global.yaml");
|
|
10839
11476
|
}
|
|
10840
11477
|
}
|
|
10841
11478
|
ensureDir() {
|
|
10842
11479
|
const dir = dirname5(this.filePath);
|
|
10843
|
-
if (!
|
|
10844
|
-
|
|
11480
|
+
if (!existsSync26(dir)) {
|
|
11481
|
+
mkdirSync14(dir, { recursive: true });
|
|
10845
11482
|
}
|
|
10846
11483
|
}
|
|
10847
11484
|
load() {
|
|
10848
11485
|
if (this.data) return this.data;
|
|
10849
|
-
if (
|
|
11486
|
+
if (existsSync26(this.filePath)) {
|
|
10850
11487
|
try {
|
|
10851
|
-
const content =
|
|
11488
|
+
const content = readFileSync16(this.filePath, "utf-8");
|
|
10852
11489
|
this.data = parseYaml8(content);
|
|
10853
11490
|
} catch {
|
|
10854
11491
|
this.data = this.createEmpty();
|
|
@@ -10867,7 +11504,7 @@ var LearningStore = class {
|
|
|
10867
11504
|
save() {
|
|
10868
11505
|
this.ensureDir();
|
|
10869
11506
|
const content = stringifyYaml6(this.data, { lineWidth: 0 });
|
|
10870
|
-
|
|
11507
|
+
writeFileSync14(this.filePath, content, "utf-8");
|
|
10871
11508
|
}
|
|
10872
11509
|
add(learning) {
|
|
10873
11510
|
const data = this.load();
|
|
@@ -10974,7 +11611,7 @@ var LearningStore = class {
|
|
|
10974
11611
|
this.save();
|
|
10975
11612
|
}
|
|
10976
11613
|
exists() {
|
|
10977
|
-
return
|
|
11614
|
+
return existsSync26(this.filePath);
|
|
10978
11615
|
}
|
|
10979
11616
|
getScope() {
|
|
10980
11617
|
return this.scope;
|
|
@@ -10982,26 +11619,26 @@ var LearningStore = class {
|
|
|
10982
11619
|
};
|
|
10983
11620
|
|
|
10984
11621
|
// src/memory/memory-index.ts
|
|
10985
|
-
import { existsSync as
|
|
10986
|
-
import { dirname as dirname6, join as
|
|
11622
|
+
import { existsSync as existsSync27, mkdirSync as mkdirSync15, readFileSync as readFileSync17, writeFileSync as writeFileSync15 } from "fs";
|
|
11623
|
+
import { dirname as dirname6, join as join26 } from "path";
|
|
10987
11624
|
import { parse as parseYaml9, stringify as stringifyYaml7 } from "yaml";
|
|
10988
11625
|
var MemoryIndexStore = class {
|
|
10989
11626
|
filePath;
|
|
10990
11627
|
data = null;
|
|
10991
11628
|
constructor(basePath, _isGlobal = false) {
|
|
10992
|
-
this.filePath =
|
|
11629
|
+
this.filePath = join26(basePath, ".skillkit", "memory", "index.yaml");
|
|
10993
11630
|
}
|
|
10994
11631
|
ensureDir() {
|
|
10995
11632
|
const dir = dirname6(this.filePath);
|
|
10996
|
-
if (!
|
|
10997
|
-
|
|
11633
|
+
if (!existsSync27(dir)) {
|
|
11634
|
+
mkdirSync15(dir, { recursive: true });
|
|
10998
11635
|
}
|
|
10999
11636
|
}
|
|
11000
11637
|
load() {
|
|
11001
11638
|
if (this.data) return this.data;
|
|
11002
|
-
if (
|
|
11639
|
+
if (existsSync27(this.filePath)) {
|
|
11003
11640
|
try {
|
|
11004
|
-
const content =
|
|
11641
|
+
const content = readFileSync17(this.filePath, "utf-8");
|
|
11005
11642
|
this.data = parseYaml9(content);
|
|
11006
11643
|
} catch {
|
|
11007
11644
|
this.data = this.createEmpty();
|
|
@@ -11025,7 +11662,7 @@ var MemoryIndexStore = class {
|
|
|
11025
11662
|
this.data.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
|
|
11026
11663
|
}
|
|
11027
11664
|
const content = stringifyYaml7(this.data, { lineWidth: 0 });
|
|
11028
|
-
|
|
11665
|
+
writeFileSync15(this.filePath, content, "utf-8");
|
|
11029
11666
|
}
|
|
11030
11667
|
extractKeywords(text) {
|
|
11031
11668
|
const stopWords = /* @__PURE__ */ new Set([
|
|
@@ -11219,7 +11856,7 @@ var MemoryIndexStore = class {
|
|
|
11219
11856
|
this.save();
|
|
11220
11857
|
}
|
|
11221
11858
|
exists() {
|
|
11222
|
-
return
|
|
11859
|
+
return existsSync27(this.filePath);
|
|
11223
11860
|
}
|
|
11224
11861
|
getStats() {
|
|
11225
11862
|
const data = this.load();
|
|
@@ -11232,50 +11869,50 @@ var MemoryIndexStore = class {
|
|
|
11232
11869
|
};
|
|
11233
11870
|
|
|
11234
11871
|
// src/memory/initializer.ts
|
|
11235
|
-
import { existsSync as
|
|
11236
|
-
import { join as
|
|
11872
|
+
import { existsSync as existsSync28, mkdirSync as mkdirSync16 } from "fs";
|
|
11873
|
+
import { join as join27 } from "path";
|
|
11237
11874
|
import { homedir as homedir10 } from "os";
|
|
11238
11875
|
function getMemoryPaths(projectPath) {
|
|
11239
|
-
const projectMemoryDir =
|
|
11240
|
-
const globalMemoryDir =
|
|
11876
|
+
const projectMemoryDir = join27(projectPath, ".skillkit", "memory");
|
|
11877
|
+
const globalMemoryDir = join27(homedir10(), ".skillkit", "memory");
|
|
11241
11878
|
return {
|
|
11242
11879
|
projectMemoryDir,
|
|
11243
11880
|
globalMemoryDir,
|
|
11244
|
-
observationsFile:
|
|
11245
|
-
learningsFile:
|
|
11246
|
-
indexFile:
|
|
11247
|
-
globalLearningsFile:
|
|
11248
|
-
globalIndexFile:
|
|
11881
|
+
observationsFile: join27(projectMemoryDir, "observations.yaml"),
|
|
11882
|
+
learningsFile: join27(projectMemoryDir, "learnings.yaml"),
|
|
11883
|
+
indexFile: join27(projectMemoryDir, "index.yaml"),
|
|
11884
|
+
globalLearningsFile: join27(globalMemoryDir, "global.yaml"),
|
|
11885
|
+
globalIndexFile: join27(globalMemoryDir, "index.yaml")
|
|
11249
11886
|
};
|
|
11250
11887
|
}
|
|
11251
11888
|
function initializeMemoryDirectory(projectPath) {
|
|
11252
11889
|
const paths = getMemoryPaths(projectPath);
|
|
11253
|
-
if (!
|
|
11254
|
-
|
|
11890
|
+
if (!existsSync28(paths.projectMemoryDir)) {
|
|
11891
|
+
mkdirSync16(paths.projectMemoryDir, { recursive: true });
|
|
11255
11892
|
}
|
|
11256
|
-
if (!
|
|
11257
|
-
|
|
11893
|
+
if (!existsSync28(paths.globalMemoryDir)) {
|
|
11894
|
+
mkdirSync16(paths.globalMemoryDir, { recursive: true });
|
|
11258
11895
|
}
|
|
11259
11896
|
return paths;
|
|
11260
11897
|
}
|
|
11261
11898
|
function memoryDirectoryExists(projectPath) {
|
|
11262
11899
|
const paths = getMemoryPaths(projectPath);
|
|
11263
|
-
return
|
|
11900
|
+
return existsSync28(paths.projectMemoryDir);
|
|
11264
11901
|
}
|
|
11265
11902
|
function globalMemoryDirectoryExists() {
|
|
11266
|
-
const globalMemoryDir =
|
|
11267
|
-
return
|
|
11903
|
+
const globalMemoryDir = join27(homedir10(), ".skillkit", "memory");
|
|
11904
|
+
return existsSync28(globalMemoryDir);
|
|
11268
11905
|
}
|
|
11269
11906
|
function getMemoryStatus(projectPath) {
|
|
11270
11907
|
const paths = getMemoryPaths(projectPath);
|
|
11271
11908
|
return {
|
|
11272
|
-
projectMemoryExists:
|
|
11273
|
-
globalMemoryExists:
|
|
11274
|
-
hasObservations:
|
|
11275
|
-
hasLearnings:
|
|
11276
|
-
hasGlobalLearnings:
|
|
11277
|
-
hasIndex:
|
|
11278
|
-
hasGlobalIndex:
|
|
11909
|
+
projectMemoryExists: existsSync28(paths.projectMemoryDir),
|
|
11910
|
+
globalMemoryExists: existsSync28(paths.globalMemoryDir),
|
|
11911
|
+
hasObservations: existsSync28(paths.observationsFile),
|
|
11912
|
+
hasLearnings: existsSync28(paths.learningsFile),
|
|
11913
|
+
hasGlobalLearnings: existsSync28(paths.globalLearningsFile),
|
|
11914
|
+
hasIndex: existsSync28(paths.indexFile),
|
|
11915
|
+
hasGlobalIndex: existsSync28(paths.globalIndexFile)
|
|
11279
11916
|
};
|
|
11280
11917
|
}
|
|
11281
11918
|
|
|
@@ -13961,8 +14598,8 @@ function createMemoryHookManager(projectPath, agent = "claude-code", config = {}
|
|
|
13961
14598
|
}
|
|
13962
14599
|
|
|
13963
14600
|
// src/memory/claude-md-updater.ts
|
|
13964
|
-
import { existsSync as
|
|
13965
|
-
import { join as
|
|
14601
|
+
import { existsSync as existsSync29, readFileSync as readFileSync18, writeFileSync as writeFileSync16, mkdirSync as mkdirSync17 } from "fs";
|
|
14602
|
+
import { join as join28, dirname as dirname7, basename as basename11 } from "path";
|
|
13966
14603
|
import { homedir as homedir12 } from "os";
|
|
13967
14604
|
var SKILLKIT_MARKER = "<!-- Auto-populated by SkillKit -->";
|
|
13968
14605
|
var DEFAULT_UPDATE_OPTIONS = {
|
|
@@ -13978,20 +14615,20 @@ var ClaudeMdUpdater = class {
|
|
|
13978
14615
|
claudeMdPath;
|
|
13979
14616
|
constructor(projectPath, claudeMdPath) {
|
|
13980
14617
|
this.projectPath = projectPath;
|
|
13981
|
-
this.claudeMdPath = claudeMdPath ||
|
|
14618
|
+
this.claudeMdPath = claudeMdPath || join28(projectPath, "CLAUDE.md");
|
|
13982
14619
|
}
|
|
13983
14620
|
/**
|
|
13984
14621
|
* Parse CLAUDE.md to extract structure
|
|
13985
14622
|
*/
|
|
13986
14623
|
parse() {
|
|
13987
|
-
if (!
|
|
14624
|
+
if (!existsSync29(this.claudeMdPath)) {
|
|
13988
14625
|
return {
|
|
13989
14626
|
content: "",
|
|
13990
14627
|
sections: /* @__PURE__ */ new Map(),
|
|
13991
14628
|
hasLearnedSection: false
|
|
13992
14629
|
};
|
|
13993
14630
|
}
|
|
13994
|
-
const content =
|
|
14631
|
+
const content = readFileSync18(this.claudeMdPath, "utf-8");
|
|
13995
14632
|
const sections = /* @__PURE__ */ new Map();
|
|
13996
14633
|
const lines = content.split("\n");
|
|
13997
14634
|
let currentSection = null;
|
|
@@ -14118,10 +14755,10 @@ var ClaudeMdUpdater = class {
|
|
|
14118
14755
|
newContent = this.createNewClaudeMd(newSection);
|
|
14119
14756
|
}
|
|
14120
14757
|
const dir = dirname7(this.claudeMdPath);
|
|
14121
|
-
if (!
|
|
14122
|
-
|
|
14758
|
+
if (!existsSync29(dir)) {
|
|
14759
|
+
mkdirSync17(dir, { recursive: true });
|
|
14123
14760
|
}
|
|
14124
|
-
|
|
14761
|
+
writeFileSync16(this.claudeMdPath, newContent, "utf-8");
|
|
14125
14762
|
return {
|
|
14126
14763
|
updated: true,
|
|
14127
14764
|
path: this.claudeMdPath,
|
|
@@ -14146,7 +14783,7 @@ var ClaudeMdUpdater = class {
|
|
|
14146
14783
|
* Check if CLAUDE.md exists
|
|
14147
14784
|
*/
|
|
14148
14785
|
exists() {
|
|
14149
|
-
return
|
|
14786
|
+
return existsSync29(this.claudeMdPath);
|
|
14150
14787
|
}
|
|
14151
14788
|
/**
|
|
14152
14789
|
* Get CLAUDE.md path
|
|
@@ -14250,7 +14887,7 @@ function updateClaudeMd(projectPath, options = {}) {
|
|
|
14250
14887
|
return updater.update(options);
|
|
14251
14888
|
}
|
|
14252
14889
|
function syncGlobalClaudeMd(options = {}) {
|
|
14253
|
-
const globalClaudeMdPath =
|
|
14890
|
+
const globalClaudeMdPath = join28(homedir12(), ".claude", "CLAUDE.md");
|
|
14254
14891
|
const updater = new ClaudeMdUpdater(homedir12(), globalClaudeMdPath);
|
|
14255
14892
|
const globalOpts = {
|
|
14256
14893
|
...options,
|
|
@@ -14570,9 +15207,9 @@ function createProgressiveDisclosureManager(projectPath, projectName) {
|
|
|
14570
15207
|
}
|
|
14571
15208
|
|
|
14572
15209
|
// src/team/manager.ts
|
|
14573
|
-
import { existsSync as
|
|
14574
|
-
import { join as
|
|
14575
|
-
import { execSync as
|
|
15210
|
+
import { existsSync as existsSync30, readFileSync as readFileSync19, writeFileSync as writeFileSync17, mkdirSync as mkdirSync18 } from "fs";
|
|
15211
|
+
import { join as join29, dirname as dirname8 } from "path";
|
|
15212
|
+
import { execSync as execSync7 } from "child_process";
|
|
14576
15213
|
import { parse as yamlParse, stringify as yamlStringify } from "yaml";
|
|
14577
15214
|
var TEAM_CONFIG_FILE = "team.yaml";
|
|
14578
15215
|
var TEAM_DIR = ".skillkit/team";
|
|
@@ -14592,9 +15229,9 @@ var TeamManager = class {
|
|
|
14592
15229
|
...config,
|
|
14593
15230
|
teamId
|
|
14594
15231
|
};
|
|
14595
|
-
const teamDir =
|
|
14596
|
-
if (!
|
|
14597
|
-
|
|
15232
|
+
const teamDir = join29(this.projectPath, TEAM_DIR);
|
|
15233
|
+
if (!existsSync30(teamDir)) {
|
|
15234
|
+
mkdirSync18(teamDir, { recursive: true });
|
|
14598
15235
|
}
|
|
14599
15236
|
this.saveConfig(fullConfig);
|
|
14600
15237
|
this.config = fullConfig;
|
|
@@ -14614,12 +15251,12 @@ var TeamManager = class {
|
|
|
14614
15251
|
* Load existing team configuration
|
|
14615
15252
|
*/
|
|
14616
15253
|
load() {
|
|
14617
|
-
const configPath =
|
|
14618
|
-
if (!
|
|
15254
|
+
const configPath = join29(this.projectPath, TEAM_DIR, TEAM_CONFIG_FILE);
|
|
15255
|
+
if (!existsSync30(configPath)) {
|
|
14619
15256
|
return null;
|
|
14620
15257
|
}
|
|
14621
15258
|
try {
|
|
14622
|
-
const content =
|
|
15259
|
+
const content = readFileSync19(configPath, "utf-8");
|
|
14623
15260
|
this.config = this.parseYaml(content);
|
|
14624
15261
|
this.loadRegistry();
|
|
14625
15262
|
return this.config;
|
|
@@ -14650,8 +15287,8 @@ var TeamManager = class {
|
|
|
14650
15287
|
if (!skillPath) {
|
|
14651
15288
|
throw new Error(`Skill "${options.skillName}" not found locally.`);
|
|
14652
15289
|
}
|
|
14653
|
-
const skillMdPath =
|
|
14654
|
-
const skillContent =
|
|
15290
|
+
const skillMdPath = join29(skillPath, "SKILL.md");
|
|
15291
|
+
const skillContent = existsSync30(skillMdPath) ? readFileSync19(skillMdPath, "utf-8") : "";
|
|
14655
15292
|
const metadata = this.extractFrontmatter(skillContent);
|
|
14656
15293
|
const shared = {
|
|
14657
15294
|
name: options.skillName,
|
|
@@ -14716,7 +15353,7 @@ var TeamManager = class {
|
|
|
14716
15353
|
if (options.dryRun) {
|
|
14717
15354
|
return {
|
|
14718
15355
|
success: true,
|
|
14719
|
-
path:
|
|
15356
|
+
path: join29(this.projectPath, ".skillkit", "skills", skillName)
|
|
14720
15357
|
};
|
|
14721
15358
|
}
|
|
14722
15359
|
try {
|
|
@@ -14766,9 +15403,9 @@ var TeamManager = class {
|
|
|
14766
15403
|
if (!fetchResult.success || !fetchResult.path) {
|
|
14767
15404
|
throw new Error(fetchResult.error || "Failed to fetch remote registry");
|
|
14768
15405
|
}
|
|
14769
|
-
const remoteRegistryPath =
|
|
14770
|
-
if (
|
|
14771
|
-
const remoteContent =
|
|
15406
|
+
const remoteRegistryPath = join29(fetchResult.path, TEAM_DIR, "registry.yaml");
|
|
15407
|
+
if (existsSync30(remoteRegistryPath)) {
|
|
15408
|
+
const remoteContent = readFileSync19(remoteRegistryPath, "utf-8");
|
|
14772
15409
|
const remoteRegistry = this.parseYaml(remoteContent);
|
|
14773
15410
|
const localSkillNames = new Set(this.registry?.skills.map((s) => s.name) || []);
|
|
14774
15411
|
for (const skill of remoteRegistry.skills) {
|
|
@@ -14814,32 +15451,32 @@ var TeamManager = class {
|
|
|
14814
15451
|
return `team-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
14815
15452
|
}
|
|
14816
15453
|
saveConfig(config) {
|
|
14817
|
-
const configPath =
|
|
15454
|
+
const configPath = join29(this.projectPath, TEAM_DIR, TEAM_CONFIG_FILE);
|
|
14818
15455
|
const dir = dirname8(configPath);
|
|
14819
|
-
if (!
|
|
14820
|
-
|
|
15456
|
+
if (!existsSync30(dir)) {
|
|
15457
|
+
mkdirSync18(dir, { recursive: true });
|
|
14821
15458
|
}
|
|
14822
|
-
|
|
15459
|
+
writeFileSync17(configPath, this.toYaml(config), "utf-8");
|
|
14823
15460
|
}
|
|
14824
15461
|
loadRegistry() {
|
|
14825
|
-
const registryPath =
|
|
14826
|
-
if (
|
|
14827
|
-
const content =
|
|
15462
|
+
const registryPath = join29(this.projectPath, TEAM_DIR, "registry.yaml");
|
|
15463
|
+
if (existsSync30(registryPath)) {
|
|
15464
|
+
const content = readFileSync19(registryPath, "utf-8");
|
|
14828
15465
|
this.registry = this.parseYaml(content);
|
|
14829
15466
|
}
|
|
14830
15467
|
}
|
|
14831
15468
|
saveRegistry(registry) {
|
|
14832
|
-
const registryPath =
|
|
14833
|
-
|
|
15469
|
+
const registryPath = join29(this.projectPath, TEAM_DIR, "registry.yaml");
|
|
15470
|
+
writeFileSync17(registryPath, this.toYaml(registry), "utf-8");
|
|
14834
15471
|
}
|
|
14835
15472
|
findLocalSkill(skillName) {
|
|
14836
15473
|
const possiblePaths = [
|
|
14837
|
-
|
|
14838
|
-
|
|
14839
|
-
|
|
15474
|
+
join29(this.projectPath, ".skillkit", "skills", skillName),
|
|
15475
|
+
join29(this.projectPath, "skills", skillName),
|
|
15476
|
+
join29(this.projectPath, ".claude", "skills", skillName)
|
|
14840
15477
|
];
|
|
14841
15478
|
for (const p of possiblePaths) {
|
|
14842
|
-
if (
|
|
15479
|
+
if (existsSync30(p)) {
|
|
14843
15480
|
return p;
|
|
14844
15481
|
}
|
|
14845
15482
|
}
|
|
@@ -14847,8 +15484,8 @@ var TeamManager = class {
|
|
|
14847
15484
|
}
|
|
14848
15485
|
getAuthor() {
|
|
14849
15486
|
try {
|
|
14850
|
-
const name =
|
|
14851
|
-
const email =
|
|
15487
|
+
const name = execSync7("git config user.name", { encoding: "utf-8" }).trim();
|
|
15488
|
+
const email = execSync7("git config user.email", { encoding: "utf-8" }).trim();
|
|
14852
15489
|
return email ? `${name} <${email}>` : name;
|
|
14853
15490
|
} catch {
|
|
14854
15491
|
return "Unknown";
|
|
@@ -14856,13 +15493,13 @@ var TeamManager = class {
|
|
|
14856
15493
|
}
|
|
14857
15494
|
detectCompatibleAgents(skillPath) {
|
|
14858
15495
|
const agents = [];
|
|
14859
|
-
if (
|
|
15496
|
+
if (existsSync30(join29(skillPath, "SKILL.md"))) {
|
|
14860
15497
|
agents.push("claude-code", "codex", "gemini-cli", "universal");
|
|
14861
15498
|
}
|
|
14862
|
-
if (
|
|
15499
|
+
if (existsSync30(join29(skillPath, "skill.mdc"))) {
|
|
14863
15500
|
agents.push("cursor");
|
|
14864
15501
|
}
|
|
14865
|
-
if (
|
|
15502
|
+
if (existsSync30(join29(skillPath, "rules.md"))) {
|
|
14866
15503
|
agents.push("windsurf");
|
|
14867
15504
|
}
|
|
14868
15505
|
return agents.length > 0 ? agents : ["universal"];
|
|
@@ -14888,8 +15525,8 @@ function createTeamManager(projectPath) {
|
|
|
14888
15525
|
}
|
|
14889
15526
|
|
|
14890
15527
|
// src/team/bundle.ts
|
|
14891
|
-
import { existsSync as
|
|
14892
|
-
import { join as
|
|
15528
|
+
import { existsSync as existsSync31, readFileSync as readFileSync20, writeFileSync as writeFileSync18, mkdirSync as mkdirSync19, readdirSync as readdirSync7, statSync as statSync3 } from "fs";
|
|
15529
|
+
import { join as join30, basename as basename12, resolve as resolve4, relative, dirname as dirname9, sep as sep3 } from "path";
|
|
14893
15530
|
import { createHash } from "crypto";
|
|
14894
15531
|
var BUNDLE_VERSION = 1;
|
|
14895
15532
|
var SkillBundle = class {
|
|
@@ -14971,15 +15608,15 @@ var SkillBundle = class {
|
|
|
14971
15608
|
readSkillContent(skillPath) {
|
|
14972
15609
|
const contents = [];
|
|
14973
15610
|
const readDir = (dir, prefix = "") => {
|
|
14974
|
-
const entries =
|
|
15611
|
+
const entries = readdirSync7(dir);
|
|
14975
15612
|
for (const entry of entries) {
|
|
14976
|
-
const fullPath =
|
|
15613
|
+
const fullPath = join30(dir, entry);
|
|
14977
15614
|
const relativePath = prefix ? `${prefix}/${entry}` : entry;
|
|
14978
15615
|
const stat = statSync3(fullPath);
|
|
14979
15616
|
if (stat.isDirectory()) {
|
|
14980
15617
|
readDir(fullPath, relativePath);
|
|
14981
15618
|
} else if (stat.isFile()) {
|
|
14982
|
-
const content =
|
|
15619
|
+
const content = readFileSync20(fullPath, "utf-8");
|
|
14983
15620
|
contents.push(`--- ${relativePath} ---
|
|
14984
15621
|
${content}`);
|
|
14985
15622
|
}
|
|
@@ -14988,13 +15625,13 @@ ${content}`);
|
|
|
14988
15625
|
if (statSync3(skillPath).isDirectory()) {
|
|
14989
15626
|
readDir(skillPath);
|
|
14990
15627
|
} else {
|
|
14991
|
-
contents.push(
|
|
15628
|
+
contents.push(readFileSync20(skillPath, "utf-8"));
|
|
14992
15629
|
}
|
|
14993
15630
|
return contents.join("\n\n");
|
|
14994
15631
|
}
|
|
14995
15632
|
detectAgents(skillPath) {
|
|
14996
15633
|
const agents = [];
|
|
14997
|
-
if (
|
|
15634
|
+
if (existsSync31(skillPath) && statSync3(skillPath).isFile()) {
|
|
14998
15635
|
const fileName = basename12(skillPath).toLowerCase();
|
|
14999
15636
|
if (fileName === "skill.md") {
|
|
15000
15637
|
return ["claude-code", "codex", "gemini-cli", "universal"];
|
|
@@ -15007,13 +15644,13 @@ ${content}`);
|
|
|
15007
15644
|
}
|
|
15008
15645
|
return ["universal"];
|
|
15009
15646
|
}
|
|
15010
|
-
if (
|
|
15647
|
+
if (existsSync31(join30(skillPath, "SKILL.md"))) {
|
|
15011
15648
|
agents.push("claude-code", "codex", "gemini-cli", "universal");
|
|
15012
15649
|
}
|
|
15013
|
-
if (
|
|
15650
|
+
if (existsSync31(join30(skillPath, "skill.mdc"))) {
|
|
15014
15651
|
agents.push("cursor");
|
|
15015
15652
|
}
|
|
15016
|
-
if (
|
|
15653
|
+
if (existsSync31(join30(skillPath, "rules.md"))) {
|
|
15017
15654
|
agents.push("windsurf");
|
|
15018
15655
|
}
|
|
15019
15656
|
return agents.length > 0 ? agents : ["universal"];
|
|
@@ -15036,10 +15673,10 @@ function exportBundle(bundle, outputPath) {
|
|
|
15036
15673
|
}
|
|
15037
15674
|
}
|
|
15038
15675
|
const dir = dirname9(outputPath);
|
|
15039
|
-
if (dir && !
|
|
15040
|
-
|
|
15676
|
+
if (dir && !existsSync31(dir)) {
|
|
15677
|
+
mkdirSync19(dir, { recursive: true });
|
|
15041
15678
|
}
|
|
15042
|
-
|
|
15679
|
+
writeFileSync18(outputPath, JSON.stringify(exportData, null, 2), "utf-8");
|
|
15043
15680
|
return { success: true, path: outputPath };
|
|
15044
15681
|
} catch (err) {
|
|
15045
15682
|
return {
|
|
@@ -15052,7 +15689,7 @@ function importBundle(bundlePath, targetDir, options = {}) {
|
|
|
15052
15689
|
const imported = [];
|
|
15053
15690
|
const errors = [];
|
|
15054
15691
|
try {
|
|
15055
|
-
const content =
|
|
15692
|
+
const content = readFileSync20(bundlePath, "utf-8");
|
|
15056
15693
|
const data = JSON.parse(content);
|
|
15057
15694
|
const absoluteTargetDir = resolve4(targetDir);
|
|
15058
15695
|
for (const skill of data.manifest.skills) {
|
|
@@ -15065,19 +15702,19 @@ function importBundle(bundlePath, targetDir, options = {}) {
|
|
|
15065
15702
|
errors.push(`Skill "${skill.name}" has no content in bundle`);
|
|
15066
15703
|
continue;
|
|
15067
15704
|
}
|
|
15068
|
-
const skillDir =
|
|
15705
|
+
const skillDir = join30(absoluteTargetDir, skill.name);
|
|
15069
15706
|
const resolvedSkillDir = resolve4(skillDir);
|
|
15070
15707
|
const relativeToTarget = relative(absoluteTargetDir, resolvedSkillDir);
|
|
15071
15708
|
if (relativeToTarget.startsWith("..") || relativeToTarget.startsWith(sep3)) {
|
|
15072
15709
|
errors.push(`Skill "${skill.name}" would escape target directory`);
|
|
15073
15710
|
continue;
|
|
15074
15711
|
}
|
|
15075
|
-
if (
|
|
15712
|
+
if (existsSync31(skillDir) && !options.overwrite) {
|
|
15076
15713
|
errors.push(`Skill "${skill.name}" already exists (use --overwrite)`);
|
|
15077
15714
|
continue;
|
|
15078
15715
|
}
|
|
15079
|
-
if (!
|
|
15080
|
-
|
|
15716
|
+
if (!existsSync31(skillDir)) {
|
|
15717
|
+
mkdirSync19(skillDir, { recursive: true });
|
|
15081
15718
|
}
|
|
15082
15719
|
const files = parseSkillContent2(skillContent);
|
|
15083
15720
|
for (const [filePath, fileContent] of Object.entries(files)) {
|
|
@@ -15088,10 +15725,10 @@ function importBundle(bundlePath, targetDir, options = {}) {
|
|
|
15088
15725
|
continue;
|
|
15089
15726
|
}
|
|
15090
15727
|
const fileDir = dirname9(fullPath);
|
|
15091
|
-
if (!
|
|
15092
|
-
|
|
15728
|
+
if (!existsSync31(fileDir)) {
|
|
15729
|
+
mkdirSync19(fileDir, { recursive: true });
|
|
15093
15730
|
}
|
|
15094
|
-
|
|
15731
|
+
writeFileSync18(fullPath, fileContent, "utf-8");
|
|
15095
15732
|
}
|
|
15096
15733
|
imported.push(skill.name);
|
|
15097
15734
|
}
|
|
@@ -15120,8 +15757,8 @@ function parseSkillContent2(content) {
|
|
|
15120
15757
|
}
|
|
15121
15758
|
|
|
15122
15759
|
// src/plugins/manager.ts
|
|
15123
|
-
import { existsSync as
|
|
15124
|
-
import { join as
|
|
15760
|
+
import { existsSync as existsSync32, readFileSync as readFileSync21, writeFileSync as writeFileSync19, mkdirSync as mkdirSync20 } from "fs";
|
|
15761
|
+
import { join as join31 } from "path";
|
|
15125
15762
|
var PLUGINS_DIR = ".skillkit/plugins";
|
|
15126
15763
|
var PLUGINS_CONFIG_FILE = "plugins.json";
|
|
15127
15764
|
var PluginManager = class {
|
|
@@ -15362,22 +15999,22 @@ var PluginManager = class {
|
|
|
15362
15999
|
}
|
|
15363
16000
|
// Private helpers
|
|
15364
16001
|
loadState() {
|
|
15365
|
-
const statePath =
|
|
15366
|
-
if (
|
|
16002
|
+
const statePath = join31(this.projectPath, PLUGINS_DIR, PLUGINS_CONFIG_FILE);
|
|
16003
|
+
if (existsSync32(statePath)) {
|
|
15367
16004
|
try {
|
|
15368
|
-
return JSON.parse(
|
|
16005
|
+
return JSON.parse(readFileSync21(statePath, "utf-8"));
|
|
15369
16006
|
} catch {
|
|
15370
16007
|
}
|
|
15371
16008
|
}
|
|
15372
16009
|
return { version: 1, plugins: {} };
|
|
15373
16010
|
}
|
|
15374
16011
|
saveState() {
|
|
15375
|
-
const pluginsDir =
|
|
15376
|
-
if (!
|
|
15377
|
-
|
|
16012
|
+
const pluginsDir = join31(this.projectPath, PLUGINS_DIR);
|
|
16013
|
+
if (!existsSync32(pluginsDir)) {
|
|
16014
|
+
mkdirSync20(pluginsDir, { recursive: true });
|
|
15378
16015
|
}
|
|
15379
|
-
const statePath =
|
|
15380
|
-
|
|
16016
|
+
const statePath = join31(pluginsDir, PLUGINS_CONFIG_FILE);
|
|
16017
|
+
writeFileSync19(statePath, JSON.stringify(this.state, null, 2), "utf-8");
|
|
15381
16018
|
}
|
|
15382
16019
|
createContext() {
|
|
15383
16020
|
return {
|
|
@@ -15402,15 +16039,15 @@ function createPluginManager(projectPath) {
|
|
|
15402
16039
|
}
|
|
15403
16040
|
|
|
15404
16041
|
// src/plugins/loader.ts
|
|
15405
|
-
import { existsSync as
|
|
15406
|
-
import { join as
|
|
16042
|
+
import { existsSync as existsSync33, readFileSync as readFileSync22, readdirSync as readdirSync8, statSync as statSync4 } from "fs";
|
|
16043
|
+
import { join as join32, extname, basename as basename13, isAbsolute } from "path";
|
|
15407
16044
|
import { pathToFileURL } from "url";
|
|
15408
16045
|
var PluginLoader = class {
|
|
15409
16046
|
/**
|
|
15410
16047
|
* Load a plugin from a file path
|
|
15411
16048
|
*/
|
|
15412
16049
|
async loadFromFile(filePath) {
|
|
15413
|
-
if (!
|
|
16050
|
+
if (!existsSync33(filePath)) {
|
|
15414
16051
|
throw new Error(`Plugin file not found: ${filePath}`);
|
|
15415
16052
|
}
|
|
15416
16053
|
const ext = extname(filePath);
|
|
@@ -15452,11 +16089,11 @@ var PluginLoader = class {
|
|
|
15452
16089
|
* Load a plugin from a JSON definition (for simple plugins)
|
|
15453
16090
|
*/
|
|
15454
16091
|
loadFromJson(jsonPath) {
|
|
15455
|
-
if (!
|
|
16092
|
+
if (!existsSync33(jsonPath)) {
|
|
15456
16093
|
throw new Error(`Plugin JSON not found: ${jsonPath}`);
|
|
15457
16094
|
}
|
|
15458
16095
|
try {
|
|
15459
|
-
const content =
|
|
16096
|
+
const content = readFileSync22(jsonPath, "utf-8");
|
|
15460
16097
|
const data = JSON.parse(content);
|
|
15461
16098
|
if (!data.metadata) {
|
|
15462
16099
|
throw new Error("Invalid plugin JSON: missing metadata");
|
|
@@ -15475,13 +16112,13 @@ var PluginLoader = class {
|
|
|
15475
16112
|
* Scan a directory for plugins
|
|
15476
16113
|
*/
|
|
15477
16114
|
async scanDirectory(dirPath) {
|
|
15478
|
-
if (!
|
|
16115
|
+
if (!existsSync33(dirPath)) {
|
|
15479
16116
|
return [];
|
|
15480
16117
|
}
|
|
15481
16118
|
const plugins = [];
|
|
15482
|
-
const entries =
|
|
16119
|
+
const entries = readdirSync8(dirPath);
|
|
15483
16120
|
for (const entry of entries) {
|
|
15484
|
-
const fullPath =
|
|
16121
|
+
const fullPath = join32(dirPath, entry);
|
|
15485
16122
|
let stat;
|
|
15486
16123
|
try {
|
|
15487
16124
|
stat = statSync4(fullPath);
|
|
@@ -15489,11 +16126,11 @@ var PluginLoader = class {
|
|
|
15489
16126
|
continue;
|
|
15490
16127
|
}
|
|
15491
16128
|
if (stat.isDirectory()) {
|
|
15492
|
-
const pkgPath =
|
|
15493
|
-
const pluginPath =
|
|
15494
|
-
if (
|
|
16129
|
+
const pkgPath = join32(fullPath, "package.json");
|
|
16130
|
+
const pluginPath = join32(fullPath, "plugin.json");
|
|
16131
|
+
if (existsSync33(pkgPath)) {
|
|
15495
16132
|
try {
|
|
15496
|
-
const pkg = JSON.parse(
|
|
16133
|
+
const pkg = JSON.parse(readFileSync22(pkgPath, "utf-8"));
|
|
15497
16134
|
if ((pkg.skillkitPlugin || pkg.keywords?.includes("skillkit-plugin")) && pkg.name && typeof pkg.name === "string" && pkg.version && typeof pkg.version === "string") {
|
|
15498
16135
|
plugins.push({
|
|
15499
16136
|
name: pkg.name,
|
|
@@ -15505,9 +16142,9 @@ var PluginLoader = class {
|
|
|
15505
16142
|
}
|
|
15506
16143
|
} catch {
|
|
15507
16144
|
}
|
|
15508
|
-
} else if (
|
|
16145
|
+
} else if (existsSync33(pluginPath)) {
|
|
15509
16146
|
try {
|
|
15510
|
-
const data = JSON.parse(
|
|
16147
|
+
const data = JSON.parse(readFileSync22(pluginPath, "utf-8"));
|
|
15511
16148
|
if (data.metadata && data.metadata.name && typeof data.metadata.name === "string" && data.metadata.version && typeof data.metadata.version === "string") {
|
|
15512
16149
|
plugins.push(data.metadata);
|
|
15513
16150
|
}
|
|
@@ -15595,12 +16232,12 @@ async function loadPlugin(source) {
|
|
|
15595
16232
|
async function loadPluginsFromDirectory(dirPath) {
|
|
15596
16233
|
const loader = new PluginLoader();
|
|
15597
16234
|
const plugins = [];
|
|
15598
|
-
if (!
|
|
16235
|
+
if (!existsSync33(dirPath)) {
|
|
15599
16236
|
return plugins;
|
|
15600
16237
|
}
|
|
15601
|
-
const entries =
|
|
16238
|
+
const entries = readdirSync8(dirPath);
|
|
15602
16239
|
for (const entry of entries) {
|
|
15603
|
-
const fullPath =
|
|
16240
|
+
const fullPath = join32(dirPath, entry);
|
|
15604
16241
|
let stat;
|
|
15605
16242
|
try {
|
|
15606
16243
|
stat = statSync4(fullPath);
|
|
@@ -15609,20 +16246,20 @@ async function loadPluginsFromDirectory(dirPath) {
|
|
|
15609
16246
|
}
|
|
15610
16247
|
try {
|
|
15611
16248
|
if (stat.isDirectory()) {
|
|
15612
|
-
const indexMjsPath =
|
|
15613
|
-
const indexPath =
|
|
15614
|
-
const mainMjsPath =
|
|
15615
|
-
const mainPath =
|
|
15616
|
-
const jsonPath =
|
|
15617
|
-
if (
|
|
16249
|
+
const indexMjsPath = join32(fullPath, "index.mjs");
|
|
16250
|
+
const indexPath = join32(fullPath, "index.js");
|
|
16251
|
+
const mainMjsPath = join32(fullPath, "plugin.mjs");
|
|
16252
|
+
const mainPath = join32(fullPath, "plugin.js");
|
|
16253
|
+
const jsonPath = join32(fullPath, "plugin.json");
|
|
16254
|
+
if (existsSync33(indexMjsPath)) {
|
|
15618
16255
|
plugins.push(await loader.loadFromFile(indexMjsPath));
|
|
15619
|
-
} else if (
|
|
16256
|
+
} else if (existsSync33(indexPath)) {
|
|
15620
16257
|
plugins.push(await loader.loadFromFile(indexPath));
|
|
15621
|
-
} else if (
|
|
16258
|
+
} else if (existsSync33(mainMjsPath)) {
|
|
15622
16259
|
plugins.push(await loader.loadFromFile(mainMjsPath));
|
|
15623
|
-
} else if (
|
|
16260
|
+
} else if (existsSync33(mainPath)) {
|
|
15624
16261
|
plugins.push(await loader.loadFromFile(mainPath));
|
|
15625
|
-
} else if (
|
|
16262
|
+
} else if (existsSync33(jsonPath)) {
|
|
15626
16263
|
plugins.push(loader.loadFromJson(jsonPath));
|
|
15627
16264
|
}
|
|
15628
16265
|
} else if (stat.isFile()) {
|
|
@@ -15641,17 +16278,17 @@ async function loadPluginsFromDirectory(dirPath) {
|
|
|
15641
16278
|
}
|
|
15642
16279
|
|
|
15643
16280
|
// src/methodology/manager.ts
|
|
15644
|
-
import { existsSync as
|
|
15645
|
-
import { join as
|
|
16281
|
+
import { existsSync as existsSync36, readFileSync as readFileSync25, writeFileSync as writeFileSync20, mkdirSync as mkdirSync21 } from "fs";
|
|
16282
|
+
import { join as join35, dirname as dirname11 } from "path";
|
|
15646
16283
|
|
|
15647
16284
|
// src/methodology/loader.ts
|
|
15648
|
-
import { existsSync as
|
|
15649
|
-
import { join as
|
|
16285
|
+
import { existsSync as existsSync35, readFileSync as readFileSync24, readdirSync as readdirSync10, statSync as statSync6 } from "fs";
|
|
16286
|
+
import { join as join34, dirname as dirname10 } from "path";
|
|
15650
16287
|
import { fileURLToPath } from "url";
|
|
15651
16288
|
|
|
15652
16289
|
// src/methodology/validator.ts
|
|
15653
|
-
import { existsSync as
|
|
15654
|
-
import { join as
|
|
16290
|
+
import { existsSync as existsSync34, readFileSync as readFileSync23, readdirSync as readdirSync9, statSync as statSync5 } from "fs";
|
|
16291
|
+
import { join as join33 } from "path";
|
|
15655
16292
|
function validatePackManifest(pack) {
|
|
15656
16293
|
const errors = [];
|
|
15657
16294
|
const warnings = [];
|
|
@@ -15801,15 +16438,15 @@ function validateSkillContent(content) {
|
|
|
15801
16438
|
function validatePackDirectory(packPath) {
|
|
15802
16439
|
const errors = [];
|
|
15803
16440
|
const warnings = [];
|
|
15804
|
-
if (!
|
|
16441
|
+
if (!existsSync34(packPath)) {
|
|
15805
16442
|
errors.push({
|
|
15806
16443
|
code: "DIR_NOT_FOUND",
|
|
15807
16444
|
message: `Pack directory not found: ${packPath}`
|
|
15808
16445
|
});
|
|
15809
16446
|
return { valid: false, errors, warnings };
|
|
15810
16447
|
}
|
|
15811
|
-
const manifestPath =
|
|
15812
|
-
if (!
|
|
16448
|
+
const manifestPath = join33(packPath, "pack.json");
|
|
16449
|
+
if (!existsSync34(manifestPath)) {
|
|
15813
16450
|
errors.push({
|
|
15814
16451
|
code: "MANIFEST_NOT_FOUND",
|
|
15815
16452
|
message: "Pack must have a pack.json manifest",
|
|
@@ -15819,7 +16456,7 @@ function validatePackDirectory(packPath) {
|
|
|
15819
16456
|
}
|
|
15820
16457
|
let manifest;
|
|
15821
16458
|
try {
|
|
15822
|
-
const raw =
|
|
16459
|
+
const raw = readFileSync23(manifestPath, "utf-8");
|
|
15823
16460
|
manifest = JSON.parse(raw);
|
|
15824
16461
|
const manifestResult = validatePackManifest(manifest);
|
|
15825
16462
|
errors.push(...manifestResult.errors);
|
|
@@ -15834,8 +16471,8 @@ function validatePackDirectory(packPath) {
|
|
|
15834
16471
|
}
|
|
15835
16472
|
if (manifest.skills) {
|
|
15836
16473
|
for (const skillName of manifest.skills) {
|
|
15837
|
-
const skillDir =
|
|
15838
|
-
if (!
|
|
16474
|
+
const skillDir = join33(packPath, skillName);
|
|
16475
|
+
if (!existsSync34(skillDir)) {
|
|
15839
16476
|
errors.push({
|
|
15840
16477
|
code: "SKILL_DIR_NOT_FOUND",
|
|
15841
16478
|
message: `Skill directory not found: ${skillName}`,
|
|
@@ -15851,8 +16488,8 @@ function validatePackDirectory(packPath) {
|
|
|
15851
16488
|
});
|
|
15852
16489
|
continue;
|
|
15853
16490
|
}
|
|
15854
|
-
const skillFile =
|
|
15855
|
-
if (!
|
|
16491
|
+
const skillFile = join33(skillDir, "SKILL.md");
|
|
16492
|
+
if (!existsSync34(skillFile)) {
|
|
15856
16493
|
errors.push({
|
|
15857
16494
|
code: "SKILL_FILE_NOT_FOUND",
|
|
15858
16495
|
message: `Skill must have a SKILL.md file: ${skillName}`,
|
|
@@ -15860,7 +16497,7 @@ function validatePackDirectory(packPath) {
|
|
|
15860
16497
|
});
|
|
15861
16498
|
continue;
|
|
15862
16499
|
}
|
|
15863
|
-
const skillContent =
|
|
16500
|
+
const skillContent = readFileSync23(skillFile, "utf-8");
|
|
15864
16501
|
const skillResult = validateSkillContent(skillContent);
|
|
15865
16502
|
for (const err of skillResult.errors) {
|
|
15866
16503
|
errors.push({
|
|
@@ -15884,15 +16521,15 @@ function validatePackDirectory(packPath) {
|
|
|
15884
16521
|
}
|
|
15885
16522
|
function validateBuiltinPacks(packsDir) {
|
|
15886
16523
|
const results = /* @__PURE__ */ new Map();
|
|
15887
|
-
if (!
|
|
16524
|
+
if (!existsSync34(packsDir)) {
|
|
15888
16525
|
return results;
|
|
15889
16526
|
}
|
|
15890
|
-
const packDirs =
|
|
15891
|
-
const packPath =
|
|
16527
|
+
const packDirs = readdirSync9(packsDir).filter((name) => {
|
|
16528
|
+
const packPath = join33(packsDir, name);
|
|
15892
16529
|
return statSync5(packPath).isDirectory();
|
|
15893
16530
|
});
|
|
15894
16531
|
for (const packName of packDirs) {
|
|
15895
|
-
const packPath =
|
|
16532
|
+
const packPath = join33(packsDir, packName);
|
|
15896
16533
|
results.set(packName, validatePackDirectory(packPath));
|
|
15897
16534
|
}
|
|
15898
16535
|
return results;
|
|
@@ -15951,7 +16588,7 @@ function extractSkillMetadata(content) {
|
|
|
15951
16588
|
// src/methodology/loader.ts
|
|
15952
16589
|
var __filename = fileURLToPath(import.meta.url);
|
|
15953
16590
|
var __dirname = dirname10(__filename);
|
|
15954
|
-
var BUILTIN_PACKS_DIR =
|
|
16591
|
+
var BUILTIN_PACKS_DIR = join34(__dirname, "packs");
|
|
15955
16592
|
var MethodologyLoader = class {
|
|
15956
16593
|
packsDir;
|
|
15957
16594
|
loadedPacks = /* @__PURE__ */ new Map();
|
|
@@ -15964,11 +16601,11 @@ var MethodologyLoader = class {
|
|
|
15964
16601
|
*/
|
|
15965
16602
|
async loadAllPacks() {
|
|
15966
16603
|
const packs = [];
|
|
15967
|
-
if (!
|
|
16604
|
+
if (!existsSync35(this.packsDir)) {
|
|
15968
16605
|
return packs;
|
|
15969
16606
|
}
|
|
15970
|
-
const packDirs =
|
|
15971
|
-
const packPath =
|
|
16607
|
+
const packDirs = readdirSync10(this.packsDir).filter((name) => {
|
|
16608
|
+
const packPath = join34(this.packsDir, name);
|
|
15972
16609
|
return statSync6(packPath).isDirectory();
|
|
15973
16610
|
});
|
|
15974
16611
|
for (const packName of packDirs) {
|
|
@@ -15989,9 +16626,9 @@ var MethodologyLoader = class {
|
|
|
15989
16626
|
if (this.loadedPacks.has(packName)) {
|
|
15990
16627
|
return this.loadedPacks.get(packName);
|
|
15991
16628
|
}
|
|
15992
|
-
const packPath =
|
|
15993
|
-
const manifestPath =
|
|
15994
|
-
if (!
|
|
16629
|
+
const packPath = join34(this.packsDir, packName);
|
|
16630
|
+
const manifestPath = join34(packPath, "pack.json");
|
|
16631
|
+
if (!existsSync35(manifestPath)) {
|
|
15995
16632
|
return null;
|
|
15996
16633
|
}
|
|
15997
16634
|
const validation = validatePackDirectory(packPath);
|
|
@@ -16001,7 +16638,7 @@ var MethodologyLoader = class {
|
|
|
16001
16638
|
);
|
|
16002
16639
|
}
|
|
16003
16640
|
const manifest = JSON.parse(
|
|
16004
|
-
|
|
16641
|
+
readFileSync24(manifestPath, "utf-8")
|
|
16005
16642
|
);
|
|
16006
16643
|
this.loadedPacks.set(packName, manifest);
|
|
16007
16644
|
return manifest;
|
|
@@ -16031,11 +16668,11 @@ var MethodologyLoader = class {
|
|
|
16031
16668
|
if (this.loadedSkills.has(skillId)) {
|
|
16032
16669
|
return this.loadedSkills.get(skillId);
|
|
16033
16670
|
}
|
|
16034
|
-
const skillPath =
|
|
16035
|
-
if (!
|
|
16671
|
+
const skillPath = join34(this.packsDir, packName, skillName, "SKILL.md");
|
|
16672
|
+
if (!existsSync35(skillPath)) {
|
|
16036
16673
|
return null;
|
|
16037
16674
|
}
|
|
16038
|
-
const content =
|
|
16675
|
+
const content = readFileSync24(skillPath, "utf-8");
|
|
16039
16676
|
const rawMetadata = extractSkillMetadata(content);
|
|
16040
16677
|
const metadata = {
|
|
16041
16678
|
triggers: rawMetadata.triggers,
|
|
@@ -16114,9 +16751,9 @@ var MethodologyLoader = class {
|
|
|
16114
16751
|
* Check if a pack exists
|
|
16115
16752
|
*/
|
|
16116
16753
|
packExists(packName) {
|
|
16117
|
-
const packPath =
|
|
16118
|
-
const manifestPath =
|
|
16119
|
-
return
|
|
16754
|
+
const packPath = join34(this.packsDir, packName);
|
|
16755
|
+
const manifestPath = join34(packPath, "pack.json");
|
|
16756
|
+
return existsSync35(manifestPath);
|
|
16120
16757
|
}
|
|
16121
16758
|
/**
|
|
16122
16759
|
* Clear cache
|
|
@@ -16482,10 +17119,10 @@ var MethodologyManager = class {
|
|
|
16482
17119
|
}
|
|
16483
17120
|
// Private helpers
|
|
16484
17121
|
loadState() {
|
|
16485
|
-
const statePath =
|
|
16486
|
-
if (
|
|
17122
|
+
const statePath = join35(this.projectPath, METHODOLOGY_STATE_FILE);
|
|
17123
|
+
if (existsSync36(statePath)) {
|
|
16487
17124
|
try {
|
|
16488
|
-
return JSON.parse(
|
|
17125
|
+
return JSON.parse(readFileSync25(statePath, "utf-8"));
|
|
16489
17126
|
} catch {
|
|
16490
17127
|
}
|
|
16491
17128
|
}
|
|
@@ -16496,21 +17133,21 @@ var MethodologyManager = class {
|
|
|
16496
17133
|
};
|
|
16497
17134
|
}
|
|
16498
17135
|
saveState() {
|
|
16499
|
-
const statePath =
|
|
17136
|
+
const statePath = join35(this.projectPath, METHODOLOGY_STATE_FILE);
|
|
16500
17137
|
const dir = dirname11(statePath);
|
|
16501
|
-
if (!
|
|
16502
|
-
|
|
17138
|
+
if (!existsSync36(dir)) {
|
|
17139
|
+
mkdirSync21(dir, { recursive: true });
|
|
16503
17140
|
}
|
|
16504
|
-
|
|
17141
|
+
writeFileSync20(statePath, JSON.stringify(this.state, null, 2), "utf-8");
|
|
16505
17142
|
}
|
|
16506
17143
|
async installSkillLocally(skill) {
|
|
16507
|
-
const skillsDir =
|
|
16508
|
-
const skillDir =
|
|
16509
|
-
if (!
|
|
16510
|
-
|
|
17144
|
+
const skillsDir = join35(this.projectPath, ".skillkit", "methodology", "skills");
|
|
17145
|
+
const skillDir = join35(skillsDir, skill.pack, skill.id.split("/")[1]);
|
|
17146
|
+
if (!existsSync36(skillDir)) {
|
|
17147
|
+
mkdirSync21(skillDir, { recursive: true });
|
|
16511
17148
|
}
|
|
16512
|
-
const targetPath =
|
|
16513
|
-
|
|
17149
|
+
const targetPath = join35(skillDir, "SKILL.md");
|
|
17150
|
+
writeFileSync20(targetPath, skill.content, "utf-8");
|
|
16514
17151
|
}
|
|
16515
17152
|
async removeSkillLocally(_skillId) {
|
|
16516
17153
|
}
|
|
@@ -16538,9 +17175,9 @@ var MethodologyManager = class {
|
|
|
16538
17175
|
if (!agentDir) {
|
|
16539
17176
|
throw new Error(`Unknown agent: ${agent}`);
|
|
16540
17177
|
}
|
|
16541
|
-
const skillsDir =
|
|
16542
|
-
if (!
|
|
16543
|
-
|
|
17178
|
+
const skillsDir = join35(this.projectPath, agentDir);
|
|
17179
|
+
if (!existsSync36(skillsDir)) {
|
|
17180
|
+
mkdirSync21(skillsDir, { recursive: true });
|
|
16544
17181
|
}
|
|
16545
17182
|
const skillName = skillId.split("/")[1];
|
|
16546
17183
|
let filename;
|
|
@@ -16551,8 +17188,8 @@ var MethodologyManager = class {
|
|
|
16551
17188
|
} else {
|
|
16552
17189
|
filename = `${skillName}.md`;
|
|
16553
17190
|
}
|
|
16554
|
-
const targetPath =
|
|
16555
|
-
|
|
17191
|
+
const targetPath = join35(skillsDir, filename);
|
|
17192
|
+
writeFileSync20(targetPath, content, "utf-8");
|
|
16556
17193
|
}
|
|
16557
17194
|
detectAgents() {
|
|
16558
17195
|
const agents = [];
|
|
@@ -16575,7 +17212,7 @@ var MethodologyManager = class {
|
|
|
16575
17212
|
["windsurf", ".windsurf"]
|
|
16576
17213
|
];
|
|
16577
17214
|
for (const [agent, dir] of agentDirs) {
|
|
16578
|
-
if (
|
|
17215
|
+
if (existsSync36(join35(this.projectPath, dir))) {
|
|
16579
17216
|
agents.push(agent);
|
|
16580
17217
|
}
|
|
16581
17218
|
}
|
|
@@ -16588,8 +17225,8 @@ function createMethodologyManager(options) {
|
|
|
16588
17225
|
}
|
|
16589
17226
|
|
|
16590
17227
|
// src/hooks/manager.ts
|
|
16591
|
-
import { existsSync as
|
|
16592
|
-
import { join as
|
|
17228
|
+
import { existsSync as existsSync37, readFileSync as readFileSync26, writeFileSync as writeFileSync21, mkdirSync as mkdirSync22 } from "fs";
|
|
17229
|
+
import { join as join36, dirname as dirname12 } from "path";
|
|
16593
17230
|
import { randomUUID as randomUUID11 } from "crypto";
|
|
16594
17231
|
import { minimatch } from "minimatch";
|
|
16595
17232
|
var DEFAULT_CONFIG_PATH = ".skillkit/hooks.json";
|
|
@@ -16600,7 +17237,7 @@ var HookManager = class {
|
|
|
16600
17237
|
constructor(options) {
|
|
16601
17238
|
this.options = {
|
|
16602
17239
|
projectPath: options.projectPath,
|
|
16603
|
-
configPath: options.configPath ||
|
|
17240
|
+
configPath: options.configPath || join36(options.projectPath, DEFAULT_CONFIG_PATH),
|
|
16604
17241
|
autoLoad: options.autoLoad ?? true,
|
|
16605
17242
|
defaultInjectionMode: options.defaultInjectionMode || "reference"
|
|
16606
17243
|
};
|
|
@@ -16740,11 +17377,11 @@ var HookManager = class {
|
|
|
16740
17377
|
* Load hooks from config file
|
|
16741
17378
|
*/
|
|
16742
17379
|
load() {
|
|
16743
|
-
if (!
|
|
17380
|
+
if (!existsSync37(this.options.configPath)) {
|
|
16744
17381
|
return;
|
|
16745
17382
|
}
|
|
16746
17383
|
try {
|
|
16747
|
-
const content =
|
|
17384
|
+
const content = readFileSync26(this.options.configPath, "utf-8");
|
|
16748
17385
|
const config = JSON.parse(content);
|
|
16749
17386
|
this.hooks.clear();
|
|
16750
17387
|
for (const hook of config.hooks) {
|
|
@@ -16772,10 +17409,10 @@ var HookManager = class {
|
|
|
16772
17409
|
}
|
|
16773
17410
|
};
|
|
16774
17411
|
const dir = dirname12(this.options.configPath);
|
|
16775
|
-
if (!
|
|
16776
|
-
|
|
17412
|
+
if (!existsSync37(dir)) {
|
|
17413
|
+
mkdirSync22(dir, { recursive: true });
|
|
16777
17414
|
}
|
|
16778
|
-
|
|
17415
|
+
writeFileSync21(this.options.configPath, JSON.stringify(config, null, 2));
|
|
16779
17416
|
}
|
|
16780
17417
|
/**
|
|
16781
17418
|
* Generate agent-specific hook configuration
|
|
@@ -17017,7 +17654,7 @@ function createHookManager(options) {
|
|
|
17017
17654
|
|
|
17018
17655
|
// src/hooks/triggers.ts
|
|
17019
17656
|
import { watch } from "fs";
|
|
17020
|
-
import { join as
|
|
17657
|
+
import { join as join37, relative as relative2 } from "path";
|
|
17021
17658
|
function debounce(fn, delay) {
|
|
17022
17659
|
let timeoutId = null;
|
|
17023
17660
|
return (...args) => {
|
|
@@ -17202,7 +17839,7 @@ var SkillTriggerEngine = class {
|
|
|
17202
17839
|
{ recursive: true },
|
|
17203
17840
|
debounce((eventType, filename) => {
|
|
17204
17841
|
if (!filename) return;
|
|
17205
|
-
const relativePath = relative2(this.options.projectPath,
|
|
17842
|
+
const relativePath = relative2(this.options.projectPath, join37(this.options.projectPath, filename));
|
|
17206
17843
|
if (this.shouldIgnore(relativePath)) return;
|
|
17207
17844
|
if (eventType === "rename") {
|
|
17208
17845
|
this.triggerFileCreate(relativePath);
|
|
@@ -19645,15 +20282,194 @@ var shellExecutor = async (step, _task, _plan) => {
|
|
|
19645
20282
|
error: `Expected output "${step.expectedOutput}" not found`
|
|
19646
20283
|
};
|
|
19647
20284
|
}
|
|
19648
|
-
return { success: true, output };
|
|
19649
|
-
} catch (error) {
|
|
19650
|
-
return {
|
|
19651
|
-
success: false,
|
|
19652
|
-
output: "",
|
|
19653
|
-
error: error.message
|
|
20285
|
+
return { success: true, output };
|
|
20286
|
+
} catch (error) {
|
|
20287
|
+
return {
|
|
20288
|
+
success: false,
|
|
20289
|
+
output: "",
|
|
20290
|
+
error: error.message
|
|
20291
|
+
};
|
|
20292
|
+
}
|
|
20293
|
+
};
|
|
20294
|
+
|
|
20295
|
+
// src/plan/issue-planner.ts
|
|
20296
|
+
import { execFileSync } from "child_process";
|
|
20297
|
+
var LABEL_TAG_MAP = {
|
|
20298
|
+
bug: "fix",
|
|
20299
|
+
fix: "fix",
|
|
20300
|
+
enhancement: "feature",
|
|
20301
|
+
feature: "feature",
|
|
20302
|
+
documentation: "docs",
|
|
20303
|
+
docs: "docs",
|
|
20304
|
+
refactor: "refactor",
|
|
20305
|
+
refactoring: "refactor",
|
|
20306
|
+
test: "test",
|
|
20307
|
+
testing: "test",
|
|
20308
|
+
security: "security",
|
|
20309
|
+
performance: "performance",
|
|
20310
|
+
"good first issue": "beginner",
|
|
20311
|
+
chore: "chore",
|
|
20312
|
+
maintenance: "chore"
|
|
20313
|
+
};
|
|
20314
|
+
var FILE_PATH_REGEX = /`([a-zA-Z0-9_./\-]+\.[a-zA-Z0-9]+)`/g;
|
|
20315
|
+
var IssuePlanner = class {
|
|
20316
|
+
parseIssueRef(ref) {
|
|
20317
|
+
const urlMatch = ref.match(
|
|
20318
|
+
/github\.com\/([^/]+)\/([^/]+)\/issues\/(\d+)/
|
|
20319
|
+
);
|
|
20320
|
+
if (urlMatch) {
|
|
20321
|
+
return {
|
|
20322
|
+
owner: urlMatch[1],
|
|
20323
|
+
repo: urlMatch[2],
|
|
20324
|
+
number: parseInt(urlMatch[3], 10)
|
|
20325
|
+
};
|
|
20326
|
+
}
|
|
20327
|
+
const fullMatch = ref.match(/^([^/]+)\/([^#]+)#(\d+)$/);
|
|
20328
|
+
if (fullMatch) {
|
|
20329
|
+
return {
|
|
20330
|
+
owner: fullMatch[1],
|
|
20331
|
+
repo: fullMatch[2],
|
|
20332
|
+
number: parseInt(fullMatch[3], 10)
|
|
20333
|
+
};
|
|
20334
|
+
}
|
|
20335
|
+
const shortMatch = ref.match(/^#?(\d+)$/);
|
|
20336
|
+
if (shortMatch) {
|
|
20337
|
+
return { number: parseInt(shortMatch[1], 10) };
|
|
20338
|
+
}
|
|
20339
|
+
throw new Error(
|
|
20340
|
+
`Invalid issue reference: "${ref}". Use #123, owner/repo#123, or a GitHub URL.`
|
|
20341
|
+
);
|
|
20342
|
+
}
|
|
20343
|
+
fetchIssue(ref) {
|
|
20344
|
+
const parsed = this.parseIssueRef(ref);
|
|
20345
|
+
const args = [
|
|
20346
|
+
"issue",
|
|
20347
|
+
"view",
|
|
20348
|
+
String(parsed.number),
|
|
20349
|
+
"--json",
|
|
20350
|
+
"number,title,body,labels,assignees,url,state"
|
|
20351
|
+
];
|
|
20352
|
+
if (parsed.owner && parsed.repo) {
|
|
20353
|
+
args.push("--repo", `${parsed.owner}/${parsed.repo}`);
|
|
20354
|
+
}
|
|
20355
|
+
const result = execFileSync("gh", args, {
|
|
20356
|
+
encoding: "utf-8",
|
|
20357
|
+
timeout: 15e3
|
|
20358
|
+
});
|
|
20359
|
+
let data;
|
|
20360
|
+
try {
|
|
20361
|
+
data = JSON.parse(result);
|
|
20362
|
+
} catch {
|
|
20363
|
+
throw new Error(`Failed to parse GitHub CLI response for issue ${parsed.number}`);
|
|
20364
|
+
}
|
|
20365
|
+
return {
|
|
20366
|
+
number: data.number,
|
|
20367
|
+
title: data.title,
|
|
20368
|
+
body: data.body || "",
|
|
20369
|
+
labels: (data.labels || []).map((l) => l.name),
|
|
20370
|
+
assignees: (data.assignees || []).map((a) => a.login),
|
|
20371
|
+
url: data.url,
|
|
20372
|
+
state: data.state
|
|
20373
|
+
};
|
|
20374
|
+
}
|
|
20375
|
+
extractTasksFromBody(body) {
|
|
20376
|
+
const tasks = [];
|
|
20377
|
+
const lines = body.split("\n");
|
|
20378
|
+
for (const line of lines) {
|
|
20379
|
+
const match = line.match(/^[\s]*-\s*\[([ xX])\]\s+(.+)$/);
|
|
20380
|
+
if (match) {
|
|
20381
|
+
tasks.push({
|
|
20382
|
+
name: match[2].trim(),
|
|
20383
|
+
checked: match[1] !== " "
|
|
20384
|
+
});
|
|
20385
|
+
}
|
|
20386
|
+
}
|
|
20387
|
+
return tasks;
|
|
20388
|
+
}
|
|
20389
|
+
extractFileMentions(text) {
|
|
20390
|
+
const files = /* @__PURE__ */ new Set();
|
|
20391
|
+
let match;
|
|
20392
|
+
const regex = new RegExp(FILE_PATH_REGEX.source, "g");
|
|
20393
|
+
while ((match = regex.exec(text)) !== null) {
|
|
20394
|
+
const path4 = match[1];
|
|
20395
|
+
if (path4.includes("/") || path4.includes(".")) {
|
|
20396
|
+
files.add(path4);
|
|
20397
|
+
}
|
|
20398
|
+
}
|
|
20399
|
+
return [...files];
|
|
20400
|
+
}
|
|
20401
|
+
inferLabelsToTags(labels) {
|
|
20402
|
+
const tags = [];
|
|
20403
|
+
for (const label of labels) {
|
|
20404
|
+
const tag = LABEL_TAG_MAP[label.toLowerCase()];
|
|
20405
|
+
if (tag && !tags.includes(tag)) {
|
|
20406
|
+
tags.push(tag);
|
|
20407
|
+
}
|
|
20408
|
+
}
|
|
20409
|
+
return tags;
|
|
20410
|
+
}
|
|
20411
|
+
generatePlan(issue, options) {
|
|
20412
|
+
const agent = options?.agent || "claude-code";
|
|
20413
|
+
const includeTests = options?.includeTests !== false;
|
|
20414
|
+
const bodyFirstParagraph = issue.body.split("\n\n")[0]?.trim() || issue.title;
|
|
20415
|
+
const generator = new PlanGenerator({
|
|
20416
|
+
includeTests,
|
|
20417
|
+
includeCommits: true,
|
|
20418
|
+
techStack: options?.techStack
|
|
20419
|
+
});
|
|
20420
|
+
const plan = generator.createPlan(
|
|
20421
|
+
`Issue #${issue.number}: ${issue.title}`,
|
|
20422
|
+
bodyFirstParagraph
|
|
20423
|
+
);
|
|
20424
|
+
plan.tags = this.inferLabelsToTags(issue.labels);
|
|
20425
|
+
const checklist = this.extractTasksFromBody(issue.body);
|
|
20426
|
+
const allFileMentions = this.extractFileMentions(issue.body);
|
|
20427
|
+
if (checklist.length > 0) {
|
|
20428
|
+
for (const item of checklist) {
|
|
20429
|
+
const taskFiles = this.extractFileMentions(item.name);
|
|
20430
|
+
const files = {};
|
|
20431
|
+
if (taskFiles.length > 0) {
|
|
20432
|
+
files.modify = taskFiles;
|
|
20433
|
+
}
|
|
20434
|
+
const task = generator.addTask(plan, item.name, {
|
|
20435
|
+
files,
|
|
20436
|
+
tags: item.checked ? ["done"] : void 0,
|
|
20437
|
+
steps: [
|
|
20438
|
+
{ type: "implement", description: item.name },
|
|
20439
|
+
...includeTests ? [{ type: "test", description: `Write tests for ${item.name}` }] : []
|
|
20440
|
+
]
|
|
20441
|
+
});
|
|
20442
|
+
if (item.checked) {
|
|
20443
|
+
task.status = "completed";
|
|
20444
|
+
}
|
|
20445
|
+
}
|
|
20446
|
+
} else {
|
|
20447
|
+
const files = {};
|
|
20448
|
+
if (allFileMentions.length > 0) {
|
|
20449
|
+
files.modify = allFileMentions;
|
|
20450
|
+
}
|
|
20451
|
+
generator.addTask(plan, issue.title, {
|
|
20452
|
+
description: bodyFirstParagraph,
|
|
20453
|
+
files,
|
|
20454
|
+
steps: [
|
|
20455
|
+
{ type: "implement", description: issue.title },
|
|
20456
|
+
...includeTests ? [{ type: "test", description: `Write tests for ${issue.title}` }] : []
|
|
20457
|
+
]
|
|
20458
|
+
});
|
|
20459
|
+
}
|
|
20460
|
+
plan.metadata = {
|
|
20461
|
+
issueNumber: issue.number,
|
|
20462
|
+
issueUrl: issue.url,
|
|
20463
|
+
issueLabels: issue.labels,
|
|
20464
|
+
agent,
|
|
20465
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
19654
20466
|
};
|
|
20467
|
+
return plan;
|
|
19655
20468
|
}
|
|
19656
20469
|
};
|
|
20470
|
+
function createIssuePlanner() {
|
|
20471
|
+
return new IssuePlanner();
|
|
20472
|
+
}
|
|
19657
20473
|
|
|
19658
20474
|
// src/commands/registry.ts
|
|
19659
20475
|
var CommandRegistry = class {
|
|
@@ -22505,8 +23321,8 @@ Source: ${doc.url}`;
|
|
|
22505
23321
|
};
|
|
22506
23322
|
|
|
22507
23323
|
// src/ai/context/codebase-source.ts
|
|
22508
|
-
import { existsSync as
|
|
22509
|
-
import { join as
|
|
23324
|
+
import { existsSync as existsSync38, readdirSync as readdirSync11, readFileSync as readFileSync27, statSync as statSync7 } from "fs";
|
|
23325
|
+
import { join as join38, extname as extname2, basename as basename14 } from "path";
|
|
22510
23326
|
var CodebaseSource = class {
|
|
22511
23327
|
name = "codebase";
|
|
22512
23328
|
displayName = "Local Codebase";
|
|
@@ -22534,7 +23350,7 @@ var CodebaseSource = class {
|
|
|
22534
23350
|
return chunks;
|
|
22535
23351
|
}
|
|
22536
23352
|
async isAvailable() {
|
|
22537
|
-
return
|
|
23353
|
+
return existsSync38(this.projectPath);
|
|
22538
23354
|
}
|
|
22539
23355
|
async analyzeCodebase(basePath, query) {
|
|
22540
23356
|
const patterns = [];
|
|
@@ -22551,10 +23367,10 @@ var CodebaseSource = class {
|
|
|
22551
23367
|
}
|
|
22552
23368
|
async detectFrameworks(basePath) {
|
|
22553
23369
|
const patterns = [];
|
|
22554
|
-
const packageJsonPath =
|
|
22555
|
-
if (
|
|
23370
|
+
const packageJsonPath = join38(basePath, "package.json");
|
|
23371
|
+
if (existsSync38(packageJsonPath)) {
|
|
22556
23372
|
try {
|
|
22557
|
-
const content =
|
|
23373
|
+
const content = readFileSync27(packageJsonPath, "utf-8");
|
|
22558
23374
|
const pkg = JSON.parse(content);
|
|
22559
23375
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
22560
23376
|
const frameworks = [
|
|
@@ -22581,8 +23397,8 @@ var CodebaseSource = class {
|
|
|
22581
23397
|
} catch {
|
|
22582
23398
|
}
|
|
22583
23399
|
}
|
|
22584
|
-
const pyprojectPath =
|
|
22585
|
-
if (
|
|
23400
|
+
const pyprojectPath = join38(basePath, "pyproject.toml");
|
|
23401
|
+
if (existsSync38(pyprojectPath)) {
|
|
22586
23402
|
patterns.push({
|
|
22587
23403
|
type: "framework",
|
|
22588
23404
|
name: "Python",
|
|
@@ -22591,8 +23407,8 @@ var CodebaseSource = class {
|
|
|
22591
23407
|
relevance: 0.7
|
|
22592
23408
|
});
|
|
22593
23409
|
}
|
|
22594
|
-
const cargoPath =
|
|
22595
|
-
if (
|
|
23410
|
+
const cargoPath = join38(basePath, "Cargo.toml");
|
|
23411
|
+
if (existsSync38(cargoPath)) {
|
|
22596
23412
|
patterns.push({
|
|
22597
23413
|
type: "framework",
|
|
22598
23414
|
name: "Rust",
|
|
@@ -22601,8 +23417,8 @@ var CodebaseSource = class {
|
|
|
22601
23417
|
relevance: 0.7
|
|
22602
23418
|
});
|
|
22603
23419
|
}
|
|
22604
|
-
const goModPath =
|
|
22605
|
-
if (
|
|
23420
|
+
const goModPath = join38(basePath, "go.mod");
|
|
23421
|
+
if (existsSync38(goModPath)) {
|
|
22606
23422
|
patterns.push({
|
|
22607
23423
|
type: "framework",
|
|
22608
23424
|
name: "Go",
|
|
@@ -22615,10 +23431,10 @@ var CodebaseSource = class {
|
|
|
22615
23431
|
}
|
|
22616
23432
|
async detectTestingSetup(basePath) {
|
|
22617
23433
|
const patterns = [];
|
|
22618
|
-
const packageJsonPath =
|
|
22619
|
-
if (
|
|
23434
|
+
const packageJsonPath = join38(basePath, "package.json");
|
|
23435
|
+
if (existsSync38(packageJsonPath)) {
|
|
22620
23436
|
try {
|
|
22621
|
-
const content =
|
|
23437
|
+
const content = readFileSync27(packageJsonPath, "utf-8");
|
|
22622
23438
|
const pkg = JSON.parse(content);
|
|
22623
23439
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
22624
23440
|
const testFrameworks = [
|
|
@@ -22643,10 +23459,10 @@ var CodebaseSource = class {
|
|
|
22643
23459
|
} catch {
|
|
22644
23460
|
}
|
|
22645
23461
|
}
|
|
22646
|
-
const vitestConfig =
|
|
22647
|
-
if (
|
|
23462
|
+
const vitestConfig = join38(basePath, "vitest.config.ts");
|
|
23463
|
+
if (existsSync38(vitestConfig)) {
|
|
22648
23464
|
try {
|
|
22649
|
-
const content =
|
|
23465
|
+
const content = readFileSync27(vitestConfig, "utf-8");
|
|
22650
23466
|
patterns.push({
|
|
22651
23467
|
type: "testing",
|
|
22652
23468
|
name: "Vitest Config",
|
|
@@ -22657,10 +23473,10 @@ var CodebaseSource = class {
|
|
|
22657
23473
|
} catch {
|
|
22658
23474
|
}
|
|
22659
23475
|
}
|
|
22660
|
-
const jestConfig =
|
|
22661
|
-
if (
|
|
23476
|
+
const jestConfig = join38(basePath, "jest.config.js");
|
|
23477
|
+
if (existsSync38(jestConfig)) {
|
|
22662
23478
|
try {
|
|
22663
|
-
const content =
|
|
23479
|
+
const content = readFileSync27(jestConfig, "utf-8");
|
|
22664
23480
|
patterns.push({
|
|
22665
23481
|
type: "testing",
|
|
22666
23482
|
name: "Jest Config",
|
|
@@ -22684,10 +23500,10 @@ var CodebaseSource = class {
|
|
|
22684
23500
|
{ file: "tailwind.config.ts", name: "Tailwind" }
|
|
22685
23501
|
];
|
|
22686
23502
|
for (const { file, name } of configFiles) {
|
|
22687
|
-
const filePath =
|
|
22688
|
-
if (
|
|
23503
|
+
const filePath = join38(basePath, file);
|
|
23504
|
+
if (existsSync38(filePath)) {
|
|
22689
23505
|
try {
|
|
22690
|
-
const content =
|
|
23506
|
+
const content = readFileSync27(filePath, "utf-8");
|
|
22691
23507
|
patterns.push({
|
|
22692
23508
|
type: "config",
|
|
22693
23509
|
name: `${name} Config`,
|
|
@@ -22706,12 +23522,12 @@ var CodebaseSource = class {
|
|
|
22706
23522
|
const keywords = query.toLowerCase().split(/\s+/);
|
|
22707
23523
|
const searchDirs = ["src", "lib", "app", "pages", "components"];
|
|
22708
23524
|
for (const dir of searchDirs) {
|
|
22709
|
-
const dirPath =
|
|
22710
|
-
if (
|
|
23525
|
+
const dirPath = join38(basePath, dir);
|
|
23526
|
+
if (existsSync38(dirPath)) {
|
|
22711
23527
|
const files = this.findFilesRecursive(dirPath, [".ts", ".tsx", ".js", ".jsx", ".py", ".go", ".rs"]);
|
|
22712
23528
|
for (const file of files.slice(0, 20)) {
|
|
22713
23529
|
try {
|
|
22714
|
-
const content =
|
|
23530
|
+
const content = readFileSync27(file, "utf-8");
|
|
22715
23531
|
const fileName = basename14(file).toLowerCase();
|
|
22716
23532
|
const relevance = this.calculateRelevance(fileName, content, keywords);
|
|
22717
23533
|
if (relevance > 0.3) {
|
|
@@ -22733,12 +23549,12 @@ var CodebaseSource = class {
|
|
|
22733
23549
|
findFilesRecursive(dir, extensions) {
|
|
22734
23550
|
const files = [];
|
|
22735
23551
|
try {
|
|
22736
|
-
const entries =
|
|
23552
|
+
const entries = readdirSync11(dir);
|
|
22737
23553
|
for (const entry of entries) {
|
|
22738
23554
|
if (entry.startsWith(".") || entry === "node_modules" || entry === "dist") {
|
|
22739
23555
|
continue;
|
|
22740
23556
|
}
|
|
22741
|
-
const fullPath =
|
|
23557
|
+
const fullPath = join38(dir, entry);
|
|
22742
23558
|
try {
|
|
22743
23559
|
const stat = statSync7(fullPath);
|
|
22744
23560
|
if (stat.isDirectory()) {
|
|
@@ -22984,8 +23800,8 @@ This existing skill can be composed with or referenced for patterns.`;
|
|
|
22984
23800
|
};
|
|
22985
23801
|
|
|
22986
23802
|
// src/ai/context/memory-source.ts
|
|
22987
|
-
import { existsSync as
|
|
22988
|
-
import { join as
|
|
23803
|
+
import { existsSync as existsSync39, readFileSync as readFileSync28 } from "fs";
|
|
23804
|
+
import { join as join39 } from "path";
|
|
22989
23805
|
var MemorySource = class {
|
|
22990
23806
|
name = "memory";
|
|
22991
23807
|
displayName = "Memory & Learnings";
|
|
@@ -23029,8 +23845,8 @@ ${entry.pattern}`,
|
|
|
23029
23845
|
}
|
|
23030
23846
|
async isAvailable() {
|
|
23031
23847
|
const claudeMdPath = this.findClaudeMd(this.projectPath);
|
|
23032
|
-
const memoryPath =
|
|
23033
|
-
return
|
|
23848
|
+
const memoryPath = join39(this.projectPath, ".skillkit", "memory", "observations.yaml");
|
|
23849
|
+
return existsSync39(claudeMdPath) || existsSync39(memoryPath);
|
|
23034
23850
|
}
|
|
23035
23851
|
async getMemoryPatterns(keywords) {
|
|
23036
23852
|
const patterns = [];
|
|
@@ -23047,11 +23863,11 @@ ${entry.pattern}`,
|
|
|
23047
23863
|
}
|
|
23048
23864
|
async getLearnedEntries(basePath) {
|
|
23049
23865
|
const claudeMdPath = this.findClaudeMd(basePath);
|
|
23050
|
-
if (!
|
|
23866
|
+
if (!existsSync39(claudeMdPath)) {
|
|
23051
23867
|
return [];
|
|
23052
23868
|
}
|
|
23053
23869
|
try {
|
|
23054
|
-
const content =
|
|
23870
|
+
const content = readFileSync28(claudeMdPath, "utf-8");
|
|
23055
23871
|
return this.parseLearnedSection(content);
|
|
23056
23872
|
} catch {
|
|
23057
23873
|
return [];
|
|
@@ -23137,18 +23953,18 @@ ${obs.content}
|
|
|
23137
23953
|
Relevance: ${obs.relevance}%`;
|
|
23138
23954
|
}
|
|
23139
23955
|
findClaudeMd(basePath) {
|
|
23140
|
-
const localPath =
|
|
23141
|
-
if (
|
|
23956
|
+
const localPath = join39(basePath, "CLAUDE.md");
|
|
23957
|
+
if (existsSync39(localPath)) {
|
|
23142
23958
|
return localPath;
|
|
23143
23959
|
}
|
|
23144
23960
|
const homeDir = process.env.HOME || process.env.USERPROFILE || "";
|
|
23145
|
-
const globalPath =
|
|
23146
|
-
if (
|
|
23961
|
+
const globalPath = join39(homeDir, ".claude", "CLAUDE.md");
|
|
23962
|
+
if (existsSync39(globalPath)) {
|
|
23147
23963
|
return globalPath;
|
|
23148
23964
|
}
|
|
23149
23965
|
const projectKey = basePath.replace(/[\\/]/g, "-");
|
|
23150
|
-
const projectMemoryPath =
|
|
23151
|
-
if (
|
|
23966
|
+
const projectMemoryPath = join39(homeDir, ".claude", "projects", projectKey, "memory", "MEMORY.md");
|
|
23967
|
+
if (existsSync39(projectMemoryPath)) {
|
|
23152
23968
|
return projectMemoryPath;
|
|
23153
23969
|
}
|
|
23154
23970
|
return localPath;
|
|
@@ -25560,8 +26376,8 @@ var CUSTOM_AGENT_FORMAT_MAP = {
|
|
|
25560
26376
|
};
|
|
25561
26377
|
|
|
25562
26378
|
// src/agents/parser.ts
|
|
25563
|
-
import { existsSync as
|
|
25564
|
-
import { join as
|
|
26379
|
+
import { existsSync as existsSync40, readFileSync as readFileSync29, statSync as statSync8 } from "fs";
|
|
26380
|
+
import { join as join40, basename as basename15, extname as extname3 } from "path";
|
|
25565
26381
|
import { parse as parseYaml10 } from "yaml";
|
|
25566
26382
|
function extractAgentFrontmatter(content) {
|
|
25567
26383
|
const match = content.match(/^---\s*\n([\s\S]*?)\n---/);
|
|
@@ -25579,14 +26395,14 @@ function extractAgentContent(content) {
|
|
|
25579
26395
|
return withoutFrontmatter.trim();
|
|
25580
26396
|
}
|
|
25581
26397
|
function parseAgentFile(filePath, location = "project") {
|
|
25582
|
-
if (!
|
|
26398
|
+
if (!existsSync40(filePath)) {
|
|
25583
26399
|
return null;
|
|
25584
26400
|
}
|
|
25585
26401
|
if (extname3(filePath) !== ".md") {
|
|
25586
26402
|
return null;
|
|
25587
26403
|
}
|
|
25588
26404
|
try {
|
|
25589
|
-
const content =
|
|
26405
|
+
const content = readFileSync29(filePath, "utf-8");
|
|
25590
26406
|
const rawFrontmatter = extractAgentFrontmatter(content);
|
|
25591
26407
|
const agentContent = extractAgentContent(content);
|
|
25592
26408
|
if (!rawFrontmatter) {
|
|
@@ -25638,16 +26454,16 @@ function parseAgentFile(filePath, location = "project") {
|
|
|
25638
26454
|
}
|
|
25639
26455
|
}
|
|
25640
26456
|
function parseAgentDir(dirPath, location = "project") {
|
|
25641
|
-
const agentMdPath =
|
|
25642
|
-
if (
|
|
26457
|
+
const agentMdPath = join40(dirPath, "AGENT.md");
|
|
26458
|
+
if (existsSync40(agentMdPath)) {
|
|
25643
26459
|
const agent = parseAgentFile(agentMdPath, location);
|
|
25644
26460
|
if (agent) {
|
|
25645
26461
|
agent.path = dirPath;
|
|
25646
26462
|
}
|
|
25647
26463
|
return agent;
|
|
25648
26464
|
}
|
|
25649
|
-
const indexMdPath =
|
|
25650
|
-
if (
|
|
26465
|
+
const indexMdPath = join40(dirPath, "index.md");
|
|
26466
|
+
if (existsSync40(indexMdPath)) {
|
|
25651
26467
|
const agent = parseAgentFile(indexMdPath, location);
|
|
25652
26468
|
if (agent) {
|
|
25653
26469
|
agent.path = dirPath;
|
|
@@ -25657,11 +26473,11 @@ function parseAgentDir(dirPath, location = "project") {
|
|
|
25657
26473
|
return null;
|
|
25658
26474
|
}
|
|
25659
26475
|
function loadAgentMetadata(metadataPath) {
|
|
25660
|
-
if (!
|
|
26476
|
+
if (!existsSync40(metadataPath)) {
|
|
25661
26477
|
return null;
|
|
25662
26478
|
}
|
|
25663
26479
|
try {
|
|
25664
|
-
const content =
|
|
26480
|
+
const content = readFileSync29(metadataPath, "utf-8");
|
|
25665
26481
|
const data = JSON.parse(content);
|
|
25666
26482
|
const parsed = AgentMetadata.safeParse(data);
|
|
25667
26483
|
return parsed.success ? parsed.data : null;
|
|
@@ -25762,25 +26578,25 @@ function fromCanonicalAgent(canonical, _targetFormat = "claude-agent") {
|
|
|
25762
26578
|
return lines.join("\n");
|
|
25763
26579
|
}
|
|
25764
26580
|
function readAgentContent(agentPath) {
|
|
25765
|
-
if (
|
|
26581
|
+
if (existsSync40(agentPath) && extname3(agentPath) === ".md") {
|
|
25766
26582
|
try {
|
|
25767
|
-
return
|
|
26583
|
+
return readFileSync29(agentPath, "utf-8");
|
|
25768
26584
|
} catch {
|
|
25769
26585
|
return null;
|
|
25770
26586
|
}
|
|
25771
26587
|
}
|
|
25772
|
-
const agentMdPath =
|
|
25773
|
-
if (
|
|
26588
|
+
const agentMdPath = join40(agentPath, "AGENT.md");
|
|
26589
|
+
if (existsSync40(agentMdPath)) {
|
|
25774
26590
|
try {
|
|
25775
|
-
return
|
|
26591
|
+
return readFileSync29(agentMdPath, "utf-8");
|
|
25776
26592
|
} catch {
|
|
25777
26593
|
return null;
|
|
25778
26594
|
}
|
|
25779
26595
|
}
|
|
25780
|
-
const indexMdPath =
|
|
25781
|
-
if (
|
|
26596
|
+
const indexMdPath = join40(agentPath, "index.md");
|
|
26597
|
+
if (existsSync40(indexMdPath)) {
|
|
25782
26598
|
try {
|
|
25783
|
-
return
|
|
26599
|
+
return readFileSync29(indexMdPath, "utf-8");
|
|
25784
26600
|
} catch {
|
|
25785
26601
|
return null;
|
|
25786
26602
|
}
|
|
@@ -25791,17 +26607,17 @@ function validateAgent(agentPath) {
|
|
|
25791
26607
|
const errors = [];
|
|
25792
26608
|
const warnings = [];
|
|
25793
26609
|
let filePath = agentPath;
|
|
25794
|
-
if (!
|
|
26610
|
+
if (!existsSync40(agentPath)) {
|
|
25795
26611
|
errors.push(`Agent file not found: ${agentPath}`);
|
|
25796
26612
|
return { valid: false, errors, warnings };
|
|
25797
26613
|
}
|
|
25798
26614
|
const stats = statSync8(agentPath);
|
|
25799
26615
|
if (stats.isDirectory()) {
|
|
25800
|
-
const agentMd =
|
|
25801
|
-
const indexMd =
|
|
25802
|
-
if (
|
|
26616
|
+
const agentMd = join40(agentPath, "AGENT.md");
|
|
26617
|
+
const indexMd = join40(agentPath, "index.md");
|
|
26618
|
+
if (existsSync40(agentMd)) {
|
|
25803
26619
|
filePath = agentMd;
|
|
25804
|
-
} else if (
|
|
26620
|
+
} else if (existsSync40(indexMd)) {
|
|
25805
26621
|
filePath = indexMd;
|
|
25806
26622
|
} else {
|
|
25807
26623
|
errors.push("Directory must contain AGENT.md or index.md");
|
|
@@ -25810,7 +26626,7 @@ function validateAgent(agentPath) {
|
|
|
25810
26626
|
}
|
|
25811
26627
|
let content;
|
|
25812
26628
|
try {
|
|
25813
|
-
content =
|
|
26629
|
+
content = readFileSync29(filePath, "utf-8");
|
|
25814
26630
|
} catch {
|
|
25815
26631
|
errors.push(`Cannot read file: ${filePath}`);
|
|
25816
26632
|
return { valid: false, errors, warnings };
|
|
@@ -25847,18 +26663,18 @@ function validateAgent(agentPath) {
|
|
|
25847
26663
|
}
|
|
25848
26664
|
|
|
25849
26665
|
// src/agents/discovery.ts
|
|
25850
|
-
import { existsSync as
|
|
25851
|
-
import { join as
|
|
26666
|
+
import { existsSync as existsSync41, readdirSync as readdirSync12, statSync as statSync9 } from "fs";
|
|
26667
|
+
import { join as join41, extname as extname4 } from "path";
|
|
25852
26668
|
import { homedir as homedir13 } from "os";
|
|
25853
26669
|
function discoverAgentsInDir(dir, location) {
|
|
25854
26670
|
const agents = [];
|
|
25855
|
-
if (!
|
|
26671
|
+
if (!existsSync41(dir)) {
|
|
25856
26672
|
return agents;
|
|
25857
26673
|
}
|
|
25858
26674
|
try {
|
|
25859
|
-
const entries =
|
|
26675
|
+
const entries = readdirSync12(dir, { withFileTypes: true });
|
|
25860
26676
|
for (const entry of entries) {
|
|
25861
|
-
const entryPath =
|
|
26677
|
+
const entryPath = join41(dir, entry.name);
|
|
25862
26678
|
if (entry.isFile() && extname4(entry.name) === ".md") {
|
|
25863
26679
|
const agent = parseAgentFile(entryPath, location);
|
|
25864
26680
|
if (agent) {
|
|
@@ -25879,8 +26695,8 @@ function discoverAgents(rootDir) {
|
|
|
25879
26695
|
const agents = [];
|
|
25880
26696
|
const seen = /* @__PURE__ */ new Set();
|
|
25881
26697
|
for (const searchPath of ALL_AGENT_DISCOVERY_PATHS) {
|
|
25882
|
-
const fullPath =
|
|
25883
|
-
if (
|
|
26698
|
+
const fullPath = join41(rootDir, searchPath);
|
|
26699
|
+
if (existsSync41(fullPath)) {
|
|
25884
26700
|
for (const agent of discoverAgentsInDir(fullPath, "project")) {
|
|
25885
26701
|
if (!seen.has(agent.name)) {
|
|
25886
26702
|
seen.add(agent.name);
|
|
@@ -25896,8 +26712,8 @@ function discoverAgentsForAgent(rootDir, agentType) {
|
|
|
25896
26712
|
const seen = /* @__PURE__ */ new Set();
|
|
25897
26713
|
const paths = AGENT_DISCOVERY_PATHS[agentType] || [];
|
|
25898
26714
|
for (const searchPath of paths) {
|
|
25899
|
-
const fullPath =
|
|
25900
|
-
if (
|
|
26715
|
+
const fullPath = join41(rootDir, searchPath);
|
|
26716
|
+
if (existsSync41(fullPath)) {
|
|
25901
26717
|
for (const agent of discoverAgentsInDir(fullPath, "project")) {
|
|
25902
26718
|
if (!seen.has(agent.name)) {
|
|
25903
26719
|
seen.add(agent.name);
|
|
@@ -25913,12 +26729,12 @@ function discoverGlobalAgents() {
|
|
|
25913
26729
|
const seen = /* @__PURE__ */ new Set();
|
|
25914
26730
|
const home = homedir13();
|
|
25915
26731
|
const globalPaths = [
|
|
25916
|
-
|
|
25917
|
-
|
|
25918
|
-
|
|
26732
|
+
join41(home, ".claude", "agents"),
|
|
26733
|
+
join41(home, ".skillkit", "agents"),
|
|
26734
|
+
join41(home, ".config", "skillkit", "agents")
|
|
25919
26735
|
];
|
|
25920
26736
|
for (const searchPath of globalPaths) {
|
|
25921
|
-
if (
|
|
26737
|
+
if (existsSync41(searchPath)) {
|
|
25922
26738
|
for (const agent of discoverAgentsInDir(searchPath, "global")) {
|
|
25923
26739
|
if (!seen.has(agent.name)) {
|
|
25924
26740
|
seen.add(agent.name);
|
|
@@ -25933,7 +26749,7 @@ function findAllAgents(searchDirs) {
|
|
|
25933
26749
|
const agents = [];
|
|
25934
26750
|
const seen = /* @__PURE__ */ new Set();
|
|
25935
26751
|
for (const dir of searchDirs) {
|
|
25936
|
-
if (!
|
|
26752
|
+
if (!existsSync41(dir)) continue;
|
|
25937
26753
|
const discovered = discoverAgents(dir);
|
|
25938
26754
|
for (const agent of discovered) {
|
|
25939
26755
|
if (!seen.has(agent.name)) {
|
|
@@ -25952,33 +26768,33 @@ function findAllAgents(searchDirs) {
|
|
|
25952
26768
|
}
|
|
25953
26769
|
function findAgent(name, searchDirs) {
|
|
25954
26770
|
for (const dir of searchDirs) {
|
|
25955
|
-
if (!
|
|
26771
|
+
if (!existsSync41(dir)) continue;
|
|
25956
26772
|
for (const searchPath of ALL_AGENT_DISCOVERY_PATHS) {
|
|
25957
|
-
const agentsDir =
|
|
25958
|
-
if (!
|
|
25959
|
-
const agentFile =
|
|
25960
|
-
if (
|
|
26773
|
+
const agentsDir = join41(dir, searchPath);
|
|
26774
|
+
if (!existsSync41(agentsDir)) continue;
|
|
26775
|
+
const agentFile = join41(agentsDir, `${name}.md`);
|
|
26776
|
+
if (existsSync41(agentFile)) {
|
|
25961
26777
|
return parseAgentFile(agentFile, "project");
|
|
25962
26778
|
}
|
|
25963
|
-
const agentDir =
|
|
25964
|
-
if (
|
|
26779
|
+
const agentDir = join41(agentsDir, name);
|
|
26780
|
+
if (existsSync41(agentDir) && statSync9(agentDir).isDirectory()) {
|
|
25965
26781
|
return parseAgentDir(agentDir, "project");
|
|
25966
26782
|
}
|
|
25967
26783
|
}
|
|
25968
26784
|
}
|
|
25969
26785
|
const home = homedir13();
|
|
25970
26786
|
const globalPaths = [
|
|
25971
|
-
|
|
25972
|
-
|
|
26787
|
+
join41(home, ".claude", "agents"),
|
|
26788
|
+
join41(home, ".skillkit", "agents")
|
|
25973
26789
|
];
|
|
25974
26790
|
for (const agentsDir of globalPaths) {
|
|
25975
|
-
if (!
|
|
25976
|
-
const agentFile =
|
|
25977
|
-
if (
|
|
26791
|
+
if (!existsSync41(agentsDir)) continue;
|
|
26792
|
+
const agentFile = join41(agentsDir, `${name}.md`);
|
|
26793
|
+
if (existsSync41(agentFile)) {
|
|
25978
26794
|
return parseAgentFile(agentFile, "global");
|
|
25979
26795
|
}
|
|
25980
|
-
const agentDir =
|
|
25981
|
-
if (
|
|
26796
|
+
const agentDir = join41(agentsDir, name);
|
|
26797
|
+
if (existsSync41(agentDir) && statSync9(agentDir).isDirectory()) {
|
|
25982
26798
|
return parseAgentDir(agentDir, "global");
|
|
25983
26799
|
}
|
|
25984
26800
|
}
|
|
@@ -25987,9 +26803,9 @@ function findAgent(name, searchDirs) {
|
|
|
25987
26803
|
function getAgentsDirectory(rootDir, agentType) {
|
|
25988
26804
|
const paths = AGENT_DISCOVERY_PATHS[agentType];
|
|
25989
26805
|
if (paths && paths.length > 0) {
|
|
25990
|
-
return
|
|
26806
|
+
return join41(rootDir, paths[0]);
|
|
25991
26807
|
}
|
|
25992
|
-
return
|
|
26808
|
+
return join41(rootDir, "agents");
|
|
25993
26809
|
}
|
|
25994
26810
|
function agentExists(name, searchDirs) {
|
|
25995
26811
|
return findAgent(name, searchDirs) !== null;
|
|
@@ -26007,14 +26823,14 @@ function getAgentStats(searchDirs) {
|
|
|
26007
26823
|
function discoverAgentsRecursive(rootDir, location = "project") {
|
|
26008
26824
|
const agents = [];
|
|
26009
26825
|
const seen = /* @__PURE__ */ new Set();
|
|
26010
|
-
if (!
|
|
26826
|
+
if (!existsSync41(rootDir)) {
|
|
26011
26827
|
return agents;
|
|
26012
26828
|
}
|
|
26013
26829
|
function scanDirectory(dir) {
|
|
26014
26830
|
try {
|
|
26015
|
-
const entries =
|
|
26831
|
+
const entries = readdirSync12(dir, { withFileTypes: true });
|
|
26016
26832
|
for (const entry of entries) {
|
|
26017
|
-
const entryPath =
|
|
26833
|
+
const entryPath = join41(dir, entry.name);
|
|
26018
26834
|
if (entry.isFile() && extname4(entry.name) === ".md") {
|
|
26019
26835
|
const agent = parseAgentFile(entryPath, location);
|
|
26020
26836
|
if (agent && !seen.has(agent.name)) {
|
|
@@ -26041,7 +26857,7 @@ function discoverAgentsRecursive(rootDir, location = "project") {
|
|
|
26041
26857
|
return agents;
|
|
26042
26858
|
}
|
|
26043
26859
|
function discoverAgentsFromPath(sourcePath, recursive = false, location = "project") {
|
|
26044
|
-
if (!
|
|
26860
|
+
if (!existsSync41(sourcePath)) {
|
|
26045
26861
|
return [];
|
|
26046
26862
|
}
|
|
26047
26863
|
const stats = statSync9(sourcePath);
|
|
@@ -26062,9 +26878,9 @@ function discoverAgentsFromPath(sourcePath, recursive = false, location = "proje
|
|
|
26062
26878
|
}
|
|
26063
26879
|
const agents = [];
|
|
26064
26880
|
try {
|
|
26065
|
-
const entries =
|
|
26881
|
+
const entries = readdirSync12(sourcePath, { withFileTypes: true });
|
|
26066
26882
|
for (const entry of entries) {
|
|
26067
|
-
const entryPath =
|
|
26883
|
+
const entryPath = join41(sourcePath, entry.name);
|
|
26068
26884
|
if (entry.isFile() && extname4(entry.name) === ".md") {
|
|
26069
26885
|
const a = parseAgentFile(entryPath, location);
|
|
26070
26886
|
if (a) agents.push(a);
|
|
@@ -26081,7 +26897,7 @@ function discoverAgentsFromPath(sourcePath, recursive = false, location = "proje
|
|
|
26081
26897
|
}
|
|
26082
26898
|
|
|
26083
26899
|
// src/agents/translator.ts
|
|
26084
|
-
import { join as
|
|
26900
|
+
import { join as join42 } from "path";
|
|
26085
26901
|
function translateAgent(agent, targetAgent, options) {
|
|
26086
26902
|
const canonical = toCanonicalAgent(agent);
|
|
26087
26903
|
return translateCanonicalAgent(canonical, targetAgent, options);
|
|
@@ -26302,9 +27118,9 @@ function getAgentFilename(agentName, targetAgent) {
|
|
|
26302
27118
|
function getAgentTargetDirectory(rootDir, targetAgent) {
|
|
26303
27119
|
const paths = AGENT_DISCOVERY_PATHS[targetAgent];
|
|
26304
27120
|
if (paths && paths.length > 0) {
|
|
26305
|
-
return
|
|
27121
|
+
return join42(rootDir, paths[0]);
|
|
26306
27122
|
}
|
|
26307
|
-
return
|
|
27123
|
+
return join42(rootDir, "agents");
|
|
26308
27124
|
}
|
|
26309
27125
|
function escapeYamlString(str) {
|
|
26310
27126
|
if (/[:\{\}\[\],&*#?|\-<>=!%@`]/.test(str) || str.includes("\n")) {
|
|
@@ -26491,8 +27307,8 @@ function loadAndConvertSkill(skill, options) {
|
|
|
26491
27307
|
}
|
|
26492
27308
|
|
|
26493
27309
|
// src/skill-translator.ts
|
|
26494
|
-
import { readFileSync as
|
|
26495
|
-
import { join as
|
|
27310
|
+
import { readFileSync as readFileSync30, existsSync as existsSync42, writeFileSync as writeFileSync22, mkdirSync as mkdirSync23 } from "fs";
|
|
27311
|
+
import { join as join43, basename as basename16, dirname as dirname13, resolve as resolve5, relative as relative3, isAbsolute as isAbsolute2 } from "path";
|
|
26496
27312
|
import { parse as parseYaml11, stringify as stringifyYaml8 } from "yaml";
|
|
26497
27313
|
var AGENT_SKILL_FORMATS = Object.fromEntries(
|
|
26498
27314
|
Object.entries(AGENT_CONFIG).map(([agent, config]) => [
|
|
@@ -26501,12 +27317,12 @@ var AGENT_SKILL_FORMATS = Object.fromEntries(
|
|
|
26501
27317
|
])
|
|
26502
27318
|
);
|
|
26503
27319
|
function parseSkillToCanonical(skillPath, sourceAgent) {
|
|
26504
|
-
const skillMdPath = skillPath.endsWith("SKILL.md") ? skillPath :
|
|
26505
|
-
if (!
|
|
27320
|
+
const skillMdPath = skillPath.endsWith("SKILL.md") ? skillPath : join43(skillPath, "SKILL.md");
|
|
27321
|
+
if (!existsSync42(skillMdPath)) {
|
|
26506
27322
|
return null;
|
|
26507
27323
|
}
|
|
26508
27324
|
try {
|
|
26509
|
-
const content =
|
|
27325
|
+
const content = readFileSync30(skillMdPath, "utf-8");
|
|
26510
27326
|
return parseSkillContentToCanonical(content, skillPath, sourceAgent);
|
|
26511
27327
|
} catch {
|
|
26512
27328
|
return null;
|
|
@@ -26594,7 +27410,7 @@ function translateSkillToAgent(canonical, targetAgent, options) {
|
|
|
26594
27410
|
}
|
|
26595
27411
|
const content = generateSkillContent(canonical, targetAgent, format, options);
|
|
26596
27412
|
const filename = options?.outputFilename || "SKILL.md";
|
|
26597
|
-
const targetDir = options?.outputDir ||
|
|
27413
|
+
const targetDir = options?.outputDir || join43(format.skillsDir, canonical.name);
|
|
26598
27414
|
return {
|
|
26599
27415
|
success: true,
|
|
26600
27416
|
content,
|
|
@@ -26769,7 +27585,7 @@ function writeTranslatedSkill(result, rootDir, options) {
|
|
|
26769
27585
|
error: "Resolved output path escapes rootDir"
|
|
26770
27586
|
};
|
|
26771
27587
|
}
|
|
26772
|
-
if (
|
|
27588
|
+
if (existsSync42(filePath) && options?.overwrite === false) {
|
|
26773
27589
|
return {
|
|
26774
27590
|
success: false,
|
|
26775
27591
|
path: filePath,
|
|
@@ -26777,10 +27593,10 @@ function writeTranslatedSkill(result, rootDir, options) {
|
|
|
26777
27593
|
skipped: true
|
|
26778
27594
|
};
|
|
26779
27595
|
}
|
|
26780
|
-
if (!
|
|
26781
|
-
|
|
27596
|
+
if (!existsSync42(targetPath)) {
|
|
27597
|
+
mkdirSync23(targetPath, { recursive: true });
|
|
26782
27598
|
}
|
|
26783
|
-
|
|
27599
|
+
writeFileSync22(filePath, result.content, "utf-8");
|
|
26784
27600
|
return { success: true, path: filePath };
|
|
26785
27601
|
} catch (error) {
|
|
26786
27602
|
return {
|
|
@@ -26963,16 +27779,16 @@ var getAgentSkillsDir = getSkillsDir;
|
|
|
26963
27779
|
var getAgentConfigFile = getConfigFile;
|
|
26964
27780
|
|
|
26965
27781
|
// src/manifest/index.ts
|
|
26966
|
-
import { readFileSync as
|
|
26967
|
-
import { join as
|
|
27782
|
+
import { readFileSync as readFileSync31, writeFileSync as writeFileSync23, existsSync as existsSync43 } from "fs";
|
|
27783
|
+
import { join as join44, dirname as dirname14 } from "path";
|
|
26968
27784
|
import { parse as parseYaml12, stringify as stringifyYaml9 } from "yaml";
|
|
26969
27785
|
var MANIFEST_FILENAMES = [".skills", ".skills.yaml", ".skills.yml", "skills.yaml"];
|
|
26970
27786
|
function findManifestPath(startDir = process.cwd()) {
|
|
26971
27787
|
let dir = startDir;
|
|
26972
27788
|
while (dir !== dirname14(dir)) {
|
|
26973
27789
|
for (const filename of MANIFEST_FILENAMES) {
|
|
26974
|
-
const manifestPath =
|
|
26975
|
-
if (
|
|
27790
|
+
const manifestPath = join44(dir, filename);
|
|
27791
|
+
if (existsSync43(manifestPath)) {
|
|
26976
27792
|
return manifestPath;
|
|
26977
27793
|
}
|
|
26978
27794
|
}
|
|
@@ -26982,11 +27798,11 @@ function findManifestPath(startDir = process.cwd()) {
|
|
|
26982
27798
|
}
|
|
26983
27799
|
function loadManifest(manifestPath) {
|
|
26984
27800
|
const path4 = manifestPath || findManifestPath();
|
|
26985
|
-
if (!path4 || !
|
|
27801
|
+
if (!path4 || !existsSync43(path4)) {
|
|
26986
27802
|
return null;
|
|
26987
27803
|
}
|
|
26988
27804
|
try {
|
|
26989
|
-
const content =
|
|
27805
|
+
const content = readFileSync31(path4, "utf-8");
|
|
26990
27806
|
const parsed = parseYaml12(content);
|
|
26991
27807
|
if (!parsed || typeof parsed !== "object") {
|
|
26992
27808
|
return null;
|
|
@@ -27028,7 +27844,7 @@ function normalizeSkills(skills) {
|
|
|
27028
27844
|
}).filter((s) => s.source);
|
|
27029
27845
|
}
|
|
27030
27846
|
function saveManifest(manifest, manifestPath) {
|
|
27031
|
-
const path4 = manifestPath ||
|
|
27847
|
+
const path4 = manifestPath || join44(process.cwd(), ".skills");
|
|
27032
27848
|
const content = stringifyYaml9({
|
|
27033
27849
|
version: manifest.version || 1,
|
|
27034
27850
|
skills: manifest.skills.map((s) => {
|
|
@@ -27041,7 +27857,7 @@ function saveManifest(manifest, manifestPath) {
|
|
|
27041
27857
|
...manifest.installMethod && { installMethod: manifest.installMethod },
|
|
27042
27858
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
27043
27859
|
});
|
|
27044
|
-
|
|
27860
|
+
writeFileSync23(path4, content, "utf-8");
|
|
27045
27861
|
}
|
|
27046
27862
|
function addToManifest(source, options, manifestPath) {
|
|
27047
27863
|
const existing = loadManifest(manifestPath) || {
|
|
@@ -27118,8 +27934,8 @@ function generateManifestFromInstalled(installedSkills) {
|
|
|
27118
27934
|
}
|
|
27119
27935
|
|
|
27120
27936
|
// src/quality/index.ts
|
|
27121
|
-
import { readFileSync as
|
|
27122
|
-
import { join as
|
|
27937
|
+
import { readFileSync as readFileSync32, existsSync as existsSync44 } from "fs";
|
|
27938
|
+
import { join as join45, basename as basename17 } from "path";
|
|
27123
27939
|
|
|
27124
27940
|
// src/quality/benchmark.ts
|
|
27125
27941
|
var CATEGORY_BENCHMARKS = {
|
|
@@ -27721,9 +28537,9 @@ function evaluateSkillContent(content) {
|
|
|
27721
28537
|
};
|
|
27722
28538
|
}
|
|
27723
28539
|
function evaluateSkillFile(filePath) {
|
|
27724
|
-
if (!
|
|
28540
|
+
if (!existsSync44(filePath)) return null;
|
|
27725
28541
|
try {
|
|
27726
|
-
const content =
|
|
28542
|
+
const content = readFileSync32(filePath, "utf-8");
|
|
27727
28543
|
return evaluateSkillContent(content);
|
|
27728
28544
|
} catch {
|
|
27729
28545
|
return null;
|
|
@@ -27749,11 +28565,11 @@ function checkTokenBudget(content) {
|
|
|
27749
28565
|
return null;
|
|
27750
28566
|
}
|
|
27751
28567
|
function evaluateSkillDirectory(dirPath) {
|
|
27752
|
-
const skillMdPath =
|
|
27753
|
-
if (
|
|
28568
|
+
const skillMdPath = join45(dirPath, "SKILL.md");
|
|
28569
|
+
if (existsSync44(skillMdPath)) {
|
|
27754
28570
|
const result = evaluateSkillFile(skillMdPath);
|
|
27755
28571
|
if (result) {
|
|
27756
|
-
const content =
|
|
28572
|
+
const content = readFileSync32(skillMdPath, "utf-8");
|
|
27757
28573
|
const nameWarning = checkNameDirectoryMatch(content, dirPath);
|
|
27758
28574
|
if (nameWarning) result.warnings.push(nameWarning);
|
|
27759
28575
|
const budgetWarning = checkTokenBudget(content);
|
|
@@ -27763,8 +28579,8 @@ function evaluateSkillDirectory(dirPath) {
|
|
|
27763
28579
|
}
|
|
27764
28580
|
const mdcFiles = ["index.mdc", `${basename17(dirPath)}.mdc`];
|
|
27765
28581
|
for (const file of mdcFiles) {
|
|
27766
|
-
const mdcPath =
|
|
27767
|
-
if (
|
|
28582
|
+
const mdcPath = join45(dirPath, file);
|
|
28583
|
+
if (existsSync44(mdcPath)) {
|
|
27768
28584
|
return evaluateSkillFile(mdcPath);
|
|
27769
28585
|
}
|
|
27770
28586
|
}
|
|
@@ -27934,8 +28750,8 @@ var AGENT_INSTRUCTION_TEMPLATES = {
|
|
|
27934
28750
|
};
|
|
27935
28751
|
|
|
27936
28752
|
// src/primer/analyzer.ts
|
|
27937
|
-
import { existsSync as
|
|
27938
|
-
import { join as
|
|
28753
|
+
import { existsSync as existsSync45, readFileSync as readFileSync33, readdirSync as readdirSync13 } from "fs";
|
|
28754
|
+
import { join as join46, basename as basename18, relative as relative4, sep as sep4 } from "path";
|
|
27939
28755
|
var PACKAGE_MANAGER_FILES = {
|
|
27940
28756
|
"package-lock.json": "npm",
|
|
27941
28757
|
"pnpm-lock.yaml": "pnpm",
|
|
@@ -28023,10 +28839,10 @@ var PrimerAnalyzer = class {
|
|
|
28023
28839
|
return analysis;
|
|
28024
28840
|
}
|
|
28025
28841
|
loadPackageJson() {
|
|
28026
|
-
const packageJsonPath =
|
|
28027
|
-
if (
|
|
28842
|
+
const packageJsonPath = join46(this.projectPath, "package.json");
|
|
28843
|
+
if (existsSync45(packageJsonPath)) {
|
|
28028
28844
|
try {
|
|
28029
|
-
const content =
|
|
28845
|
+
const content = readFileSync33(packageJsonPath, "utf-8");
|
|
28030
28846
|
this.packageJson = JSON.parse(content);
|
|
28031
28847
|
} catch {
|
|
28032
28848
|
this.packageJson = null;
|
|
@@ -28037,9 +28853,9 @@ var PrimerAnalyzer = class {
|
|
|
28037
28853
|
const scan = (dir, depth) => {
|
|
28038
28854
|
if (depth > maxDepth) return;
|
|
28039
28855
|
try {
|
|
28040
|
-
const entries =
|
|
28856
|
+
const entries = readdirSync13(dir, { withFileTypes: true });
|
|
28041
28857
|
for (const entry of entries) {
|
|
28042
|
-
const fullPath =
|
|
28858
|
+
const fullPath = join46(dir, entry.name);
|
|
28043
28859
|
const relativePath = relative4(this.projectPath, fullPath);
|
|
28044
28860
|
if (entry.name.startsWith(".") && entry.name !== ".github" && entry.name !== ".env.example") {
|
|
28045
28861
|
if (!entry.isDirectory()) {
|
|
@@ -28084,10 +28900,10 @@ var PrimerAnalyzer = class {
|
|
|
28084
28900
|
info.repository = String(repo.url);
|
|
28085
28901
|
}
|
|
28086
28902
|
}
|
|
28087
|
-
const pyprojectPath =
|
|
28088
|
-
if (!this.packageJson &&
|
|
28903
|
+
const pyprojectPath = join46(this.projectPath, "pyproject.toml");
|
|
28904
|
+
if (!this.packageJson && existsSync45(pyprojectPath)) {
|
|
28089
28905
|
try {
|
|
28090
|
-
const content =
|
|
28906
|
+
const content = readFileSync33(pyprojectPath, "utf-8");
|
|
28091
28907
|
const nameMatch = content.match(/name\s*=\s*["']([^"']+)["']/);
|
|
28092
28908
|
const versionMatch = content.match(/version\s*=\s*["']([^"']+)["']/);
|
|
28093
28909
|
const descMatch = content.match(/description\s*=\s*["']([^"']+)["']/);
|
|
@@ -28097,10 +28913,10 @@ var PrimerAnalyzer = class {
|
|
|
28097
28913
|
} catch {
|
|
28098
28914
|
}
|
|
28099
28915
|
}
|
|
28100
|
-
const cargoPath =
|
|
28101
|
-
if (!this.packageJson &&
|
|
28916
|
+
const cargoPath = join46(this.projectPath, "Cargo.toml");
|
|
28917
|
+
if (!this.packageJson && existsSync45(cargoPath)) {
|
|
28102
28918
|
try {
|
|
28103
|
-
const content =
|
|
28919
|
+
const content = readFileSync33(cargoPath, "utf-8");
|
|
28104
28920
|
const nameMatch = content.match(/name\s*=\s*["']([^"']+)["']/);
|
|
28105
28921
|
const versionMatch = content.match(/version\s*=\s*["']([^"']+)["']/);
|
|
28106
28922
|
const descMatch = content.match(/description\s*=\s*["']([^"']+)["']/);
|
|
@@ -28280,8 +29096,8 @@ var PrimerAnalyzer = class {
|
|
|
28280
29096
|
}
|
|
28281
29097
|
if (this.hasFile("tsconfig.json")) {
|
|
28282
29098
|
try {
|
|
28283
|
-
const tsconfigPath =
|
|
28284
|
-
const content =
|
|
29099
|
+
const tsconfigPath = join46(this.projectPath, "tsconfig.json");
|
|
29100
|
+
const content = readFileSync33(tsconfigPath, "utf-8");
|
|
28285
29101
|
const tsconfig = JSON.parse(content.replace(/\/\/.*$/gm, "").replace(/,\s*}/g, "}"));
|
|
28286
29102
|
const paths = tsconfig.compilerOptions?.paths;
|
|
28287
29103
|
if (paths && Object.keys(paths).some((k) => k.startsWith("@"))) {
|
|
@@ -28310,8 +29126,8 @@ var PrimerAnalyzer = class {
|
|
|
28310
29126
|
ci.provider = "github-actions";
|
|
28311
29127
|
ci.configFile = ".github/workflows";
|
|
28312
29128
|
try {
|
|
28313
|
-
const workflowsDir =
|
|
28314
|
-
const workflows =
|
|
29129
|
+
const workflowsDir = join46(this.projectPath, ".github/workflows");
|
|
29130
|
+
const workflows = readdirSync13(workflowsDir);
|
|
28315
29131
|
const deployWorkflows = workflows.filter(
|
|
28316
29132
|
(f) => f.includes("deploy") || f.includes("release") || f.includes("publish")
|
|
28317
29133
|
);
|
|
@@ -28331,12 +29147,12 @@ var PrimerAnalyzer = class {
|
|
|
28331
29147
|
env.hasEnvFile = this.hasFile(".env");
|
|
28332
29148
|
env.hasEnvExample = this.hasFile(".env.example") || this.hasFile(".env.template") || this.hasFile(".env.sample");
|
|
28333
29149
|
if (env.hasEnvExample) {
|
|
28334
|
-
const envExamplePath =
|
|
29150
|
+
const envExamplePath = join46(
|
|
28335
29151
|
this.projectPath,
|
|
28336
29152
|
this.hasFile(".env.example") ? ".env.example" : this.hasFile(".env.template") ? ".env.template" : ".env.sample"
|
|
28337
29153
|
);
|
|
28338
29154
|
try {
|
|
28339
|
-
const content =
|
|
29155
|
+
const content = readFileSync33(envExamplePath, "utf-8");
|
|
28340
29156
|
const variables = content.split("\n").filter((line) => line.trim() && !line.startsWith("#")).map((line) => line.split("=")[0].trim()).filter((v) => v);
|
|
28341
29157
|
env.envVariables = variables;
|
|
28342
29158
|
} catch {
|
|
@@ -28353,8 +29169,8 @@ var PrimerAnalyzer = class {
|
|
|
28353
29169
|
docker.hasCompose = this.hasFile("docker-compose.yml") || this.hasFile("docker-compose.yaml") || this.hasFile("compose.yml");
|
|
28354
29170
|
if (docker.hasDockerfile) {
|
|
28355
29171
|
try {
|
|
28356
|
-
const dockerfilePath =
|
|
28357
|
-
const content =
|
|
29172
|
+
const dockerfilePath = join46(this.projectPath, "Dockerfile");
|
|
29173
|
+
const content = readFileSync33(dockerfilePath, "utf-8");
|
|
28358
29174
|
const fromMatch = content.match(/^FROM\s+(\S+)/m);
|
|
28359
29175
|
if (fromMatch) {
|
|
28360
29176
|
docker.baseImage = fromMatch[1];
|
|
@@ -28443,7 +29259,7 @@ var PrimerAnalyzer = class {
|
|
|
28443
29259
|
}
|
|
28444
29260
|
return false;
|
|
28445
29261
|
}
|
|
28446
|
-
return this.files.has(name) ||
|
|
29262
|
+
return this.files.has(name) || existsSync45(join46(this.projectPath, name));
|
|
28447
29263
|
}
|
|
28448
29264
|
getDepVersion(dep) {
|
|
28449
29265
|
if (!this.packageJson) return void 0;
|
|
@@ -28465,10 +29281,10 @@ var PrimerAnalyzer = class {
|
|
|
28465
29281
|
}
|
|
28466
29282
|
readConfigFile(files) {
|
|
28467
29283
|
for (const file of files) {
|
|
28468
|
-
const filePath =
|
|
28469
|
-
if (
|
|
29284
|
+
const filePath = join46(this.projectPath, file);
|
|
29285
|
+
if (existsSync45(filePath)) {
|
|
28470
29286
|
try {
|
|
28471
|
-
const content =
|
|
29287
|
+
const content = readFileSync33(filePath, "utf-8");
|
|
28472
29288
|
if (file.endsWith(".json")) {
|
|
28473
29289
|
return JSON.parse(content);
|
|
28474
29290
|
}
|
|
@@ -28486,8 +29302,8 @@ function analyzePrimer(projectPath) {
|
|
|
28486
29302
|
}
|
|
28487
29303
|
|
|
28488
29304
|
// src/primer/generator.ts
|
|
28489
|
-
import { existsSync as
|
|
28490
|
-
import { join as
|
|
29305
|
+
import { existsSync as existsSync46, mkdirSync as mkdirSync24, writeFileSync as writeFileSync24 } from "fs";
|
|
29306
|
+
import { join as join47, dirname as dirname15 } from "path";
|
|
28491
29307
|
var ALL_AGENTS = Object.keys(AGENT_CONFIG);
|
|
28492
29308
|
var markdownRenderer = {
|
|
28493
29309
|
h1: (text) => `# ${text}`,
|
|
@@ -28651,14 +29467,14 @@ var PrimerGenerator = class {
|
|
|
28651
29467
|
detectInstalledAgents() {
|
|
28652
29468
|
const detected = [];
|
|
28653
29469
|
for (const [agent, config] of Object.entries(AGENT_CONFIG)) {
|
|
28654
|
-
const configPath =
|
|
28655
|
-
const skillsPath =
|
|
28656
|
-
if (
|
|
29470
|
+
const configPath = join47(this.projectPath, config.configFile);
|
|
29471
|
+
const skillsPath = join47(this.projectPath, config.skillsDir);
|
|
29472
|
+
if (existsSync46(configPath) || existsSync46(skillsPath)) {
|
|
28657
29473
|
detected.push(agent);
|
|
28658
29474
|
}
|
|
28659
29475
|
if (config.altSkillsDirs) {
|
|
28660
29476
|
for (const altDir of config.altSkillsDirs) {
|
|
28661
|
-
if (
|
|
29477
|
+
if (existsSync46(join47(this.projectPath, altDir))) {
|
|
28662
29478
|
if (!detected.includes(agent)) {
|
|
28663
29479
|
detected.push(agent);
|
|
28664
29480
|
}
|
|
@@ -28678,7 +29494,7 @@ var PrimerGenerator = class {
|
|
|
28678
29494
|
const template = AGENT_INSTRUCTION_TEMPLATES[agent] || this.getDefaultTemplate(agent, config);
|
|
28679
29495
|
const content = this.generateContent(template);
|
|
28680
29496
|
const outputDir = this.options.outputDir || this.projectPath;
|
|
28681
|
-
const filepath =
|
|
29497
|
+
const filepath = join47(outputDir, template.filename);
|
|
28682
29498
|
return {
|
|
28683
29499
|
agent,
|
|
28684
29500
|
filename: template.filename,
|
|
@@ -29051,10 +29867,10 @@ var PrimerGenerator = class {
|
|
|
29051
29867
|
}
|
|
29052
29868
|
writeInstruction(instruction) {
|
|
29053
29869
|
const dir = dirname15(instruction.filepath);
|
|
29054
|
-
if (!
|
|
29055
|
-
|
|
29870
|
+
if (!existsSync46(dir)) {
|
|
29871
|
+
mkdirSync24(dir, { recursive: true });
|
|
29056
29872
|
}
|
|
29057
|
-
|
|
29873
|
+
writeFileSync24(instruction.filepath, instruction.content, "utf-8");
|
|
29058
29874
|
}
|
|
29059
29875
|
formatProjectType(type) {
|
|
29060
29876
|
const typeMap = {
|
|
@@ -29068,402 +29884,135 @@ var PrimerGenerator = class {
|
|
|
29068
29884
|
};
|
|
29069
29885
|
return typeMap[type] || type;
|
|
29070
29886
|
}
|
|
29071
|
-
capitalize(str) {
|
|
29072
|
-
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
29073
|
-
}
|
|
29074
|
-
};
|
|
29075
|
-
function generatePrimer(projectPath, options = {}) {
|
|
29076
|
-
const generator = new PrimerGenerator(projectPath, options);
|
|
29077
|
-
return generator.generate();
|
|
29078
|
-
}
|
|
29079
|
-
function generatePrimerForAgent(projectPath, agent, options = {}) {
|
|
29080
|
-
return generatePrimer(projectPath, { ...options, agents: [agent] });
|
|
29081
|
-
}
|
|
29082
|
-
function analyzeForPrimer(projectPath) {
|
|
29083
|
-
const generator = new PrimerGenerator(projectPath, { analyzeOnly: true });
|
|
29084
|
-
const result = generator.generate();
|
|
29085
|
-
return result.analysis;
|
|
29086
|
-
}
|
|
29087
|
-
|
|
29088
|
-
// src/learning/types.ts
|
|
29089
|
-
var DEFAULT_LEARNING_CONFIG = {
|
|
29090
|
-
minSessionLength: 10,
|
|
29091
|
-
sensitivity: "medium",
|
|
29092
|
-
autoApprove: false,
|
|
29093
|
-
outputPath: "~/.skillkit/learned/",
|
|
29094
|
-
categories: ["error_fix", "refactor", "workaround", "debugging", "convention"],
|
|
29095
|
-
ignorePatterns: ["trivial_typo", "one_off_fix", "wip", "merge"]
|
|
29096
|
-
};
|
|
29097
|
-
|
|
29098
|
-
// src/learning/config.ts
|
|
29099
|
-
import { existsSync as existsSync44, readFileSync as readFileSync32, writeFileSync as writeFileSync23, mkdirSync as mkdirSync23 } from "fs";
|
|
29100
|
-
import { join as join45, dirname as dirname16 } from "path";
|
|
29101
|
-
import { homedir as homedir14 } from "os";
|
|
29102
|
-
import yaml from "yaml";
|
|
29103
|
-
function getDefaultConfigPath() {
|
|
29104
|
-
return join45(homedir14(), ".skillkit", "learning.yaml");
|
|
29105
|
-
}
|
|
29106
|
-
function getDefaultStorePath() {
|
|
29107
|
-
return join45(homedir14(), ".skillkit", "learned", "patterns.json");
|
|
29108
|
-
}
|
|
29109
|
-
function loadLearningConfig(configPath) {
|
|
29110
|
-
const path4 = configPath || getDefaultConfigPath();
|
|
29111
|
-
if (!existsSync44(path4)) {
|
|
29112
|
-
return DEFAULT_LEARNING_CONFIG;
|
|
29113
|
-
}
|
|
29114
|
-
try {
|
|
29115
|
-
const content = readFileSync32(path4, "utf-8");
|
|
29116
|
-
const config = yaml.parse(content);
|
|
29117
|
-
return { ...DEFAULT_LEARNING_CONFIG, ...config };
|
|
29118
|
-
} catch {
|
|
29119
|
-
return DEFAULT_LEARNING_CONFIG;
|
|
29120
|
-
}
|
|
29121
|
-
}
|
|
29122
|
-
function saveLearningConfig(config, configPath) {
|
|
29123
|
-
const path4 = configPath || getDefaultConfigPath();
|
|
29124
|
-
const dir = dirname16(path4);
|
|
29125
|
-
if (!existsSync44(dir)) {
|
|
29126
|
-
mkdirSync23(dir, { recursive: true });
|
|
29127
|
-
}
|
|
29128
|
-
const content = yaml.stringify(config);
|
|
29129
|
-
writeFileSync23(path4, content);
|
|
29130
|
-
}
|
|
29131
|
-
function loadPatternStore(storePath) {
|
|
29132
|
-
const path4 = storePath || getDefaultStorePath();
|
|
29133
|
-
if (!existsSync44(path4)) {
|
|
29134
|
-
return {
|
|
29135
|
-
version: 1,
|
|
29136
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
29137
|
-
patterns: [],
|
|
29138
|
-
evolvingPatterns: []
|
|
29139
|
-
};
|
|
29140
|
-
}
|
|
29141
|
-
try {
|
|
29142
|
-
const content = readFileSync32(path4, "utf-8");
|
|
29143
|
-
return JSON.parse(content);
|
|
29144
|
-
} catch {
|
|
29145
|
-
return {
|
|
29146
|
-
version: 1,
|
|
29147
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
29148
|
-
patterns: [],
|
|
29149
|
-
evolvingPatterns: []
|
|
29150
|
-
};
|
|
29151
|
-
}
|
|
29152
|
-
}
|
|
29153
|
-
function savePatternStore(store, storePath) {
|
|
29154
|
-
const path4 = storePath || getDefaultStorePath();
|
|
29155
|
-
const dir = dirname16(path4);
|
|
29156
|
-
if (!existsSync44(dir)) {
|
|
29157
|
-
mkdirSync23(dir, { recursive: true });
|
|
29158
|
-
}
|
|
29159
|
-
store.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
29160
|
-
const content = JSON.stringify(store, null, 2);
|
|
29161
|
-
writeFileSync23(path4, content);
|
|
29162
|
-
}
|
|
29163
|
-
function addPattern(pattern, storePath) {
|
|
29164
|
-
const store = loadPatternStore(storePath);
|
|
29165
|
-
const existingIndex = store.patterns.findIndex((p) => p.id === pattern.id);
|
|
29166
|
-
if (existingIndex >= 0) {
|
|
29167
|
-
store.patterns[existingIndex] = pattern;
|
|
29168
|
-
} else {
|
|
29169
|
-
store.patterns.push(pattern);
|
|
29170
|
-
}
|
|
29171
|
-
savePatternStore(store, storePath);
|
|
29172
|
-
return store;
|
|
29173
|
-
}
|
|
29174
|
-
function removePattern(patternId, storePath) {
|
|
29175
|
-
const store = loadPatternStore(storePath);
|
|
29176
|
-
store.patterns = store.patterns.filter((p) => p.id !== patternId);
|
|
29177
|
-
store.evolvingPatterns = store.evolvingPatterns.filter((p) => p.id !== patternId);
|
|
29178
|
-
savePatternStore(store, storePath);
|
|
29179
|
-
return store;
|
|
29180
|
-
}
|
|
29181
|
-
function getPattern(patternId, storePath) {
|
|
29182
|
-
const store = loadPatternStore(storePath);
|
|
29183
|
-
return store.patterns.find((p) => p.id === patternId) || null;
|
|
29184
|
-
}
|
|
29185
|
-
function getEvolvingPattern(patternId, storePath) {
|
|
29186
|
-
const store = loadPatternStore(storePath);
|
|
29187
|
-
return store.evolvingPatterns.find((p) => p.id === patternId) || null;
|
|
29188
|
-
}
|
|
29189
|
-
function getAllPatterns(storePath) {
|
|
29190
|
-
const store = loadPatternStore(storePath);
|
|
29191
|
-
return store.patterns;
|
|
29192
|
-
}
|
|
29193
|
-
function getPatternsByCategory(category, storePath) {
|
|
29194
|
-
const store = loadPatternStore(storePath);
|
|
29195
|
-
return store.patterns.filter((p) => p.category === category);
|
|
29196
|
-
}
|
|
29197
|
-
function getApprovedPatterns(storePath) {
|
|
29198
|
-
const store = loadPatternStore(storePath);
|
|
29199
|
-
return store.patterns.filter((p) => p.approved);
|
|
29200
|
-
}
|
|
29201
|
-
|
|
29202
|
-
// src/learning/git-analyzer.ts
|
|
29203
|
-
import { execSync as execSync7 } from "child_process";
|
|
29204
|
-
import { existsSync as existsSync45 } from "fs";
|
|
29205
|
-
import { join as join46 } from "path";
|
|
29206
|
-
function runGitCommand(command, cwd) {
|
|
29207
|
-
try {
|
|
29208
|
-
return execSync7(command, { cwd, encoding: "utf-8", maxBuffer: 10 * 1024 * 1024 });
|
|
29209
|
-
} catch {
|
|
29210
|
-
return "";
|
|
29211
|
-
}
|
|
29212
|
-
}
|
|
29213
|
-
function isGitRepository(path4) {
|
|
29214
|
-
return existsSync45(join46(path4, ".git"));
|
|
29215
|
-
}
|
|
29216
|
-
function getGitCommits(repoPath, options = {}) {
|
|
29217
|
-
if (!isGitRepository(repoPath)) {
|
|
29218
|
-
return [];
|
|
29219
|
-
}
|
|
29220
|
-
const limit = options.commits || 100;
|
|
29221
|
-
const args = [
|
|
29222
|
-
"log",
|
|
29223
|
-
`--max-count=${limit}`,
|
|
29224
|
-
"--format=%H|||%h|||%an|||%aI|||%s|||%b|||END_COMMIT",
|
|
29225
|
-
"--name-status"
|
|
29226
|
-
];
|
|
29227
|
-
if (options.since) {
|
|
29228
|
-
args.push(`--since="${options.since}"`);
|
|
29229
|
-
}
|
|
29230
|
-
if (options.until) {
|
|
29231
|
-
args.push(`--until="${options.until}"`);
|
|
29232
|
-
}
|
|
29233
|
-
if (options.branch) {
|
|
29234
|
-
args.push(options.branch);
|
|
29235
|
-
}
|
|
29236
|
-
if (options.author) {
|
|
29237
|
-
args.push(`--author="${options.author}"`);
|
|
29238
|
-
}
|
|
29239
|
-
const output = runGitCommand(`git ${args.join(" ")}`, repoPath);
|
|
29240
|
-
if (!output) return [];
|
|
29241
|
-
const commits = [];
|
|
29242
|
-
const commitBlocks = output.split("END_COMMIT").filter((b) => b.trim());
|
|
29243
|
-
for (const block of commitBlocks) {
|
|
29244
|
-
const lines = block.trim().split("\n");
|
|
29245
|
-
if (lines.length === 0) continue;
|
|
29246
|
-
const headerLine = lines[0];
|
|
29247
|
-
const parts = headerLine.split("|||");
|
|
29248
|
-
if (parts.length < 5) continue;
|
|
29249
|
-
const [hash, shortHash, author, date, message, body] = parts;
|
|
29250
|
-
const files = [];
|
|
29251
|
-
for (let i = 1; i < lines.length; i++) {
|
|
29252
|
-
const line = lines[i].trim();
|
|
29253
|
-
if (!line) continue;
|
|
29254
|
-
const match = line.match(/^([AMDRT])\d*\t(.+?)(?:\t(.+))?$/);
|
|
29255
|
-
if (match) {
|
|
29256
|
-
const [, status, path4, oldPath] = match;
|
|
29257
|
-
files.push({
|
|
29258
|
-
path: path4,
|
|
29259
|
-
status: parseFileStatus(status),
|
|
29260
|
-
additions: 0,
|
|
29261
|
-
deletions: 0,
|
|
29262
|
-
oldPath: oldPath || void 0
|
|
29263
|
-
});
|
|
29264
|
-
}
|
|
29265
|
-
}
|
|
29266
|
-
commits.push({
|
|
29267
|
-
hash,
|
|
29268
|
-
shortHash,
|
|
29269
|
-
author,
|
|
29270
|
-
date,
|
|
29271
|
-
message,
|
|
29272
|
-
body: body || void 0,
|
|
29273
|
-
files
|
|
29274
|
-
});
|
|
29275
|
-
}
|
|
29276
|
-
return commits;
|
|
29277
|
-
}
|
|
29278
|
-
function parseFileStatus(status) {
|
|
29279
|
-
switch (status) {
|
|
29280
|
-
case "A":
|
|
29281
|
-
return "added";
|
|
29282
|
-
case "D":
|
|
29283
|
-
return "deleted";
|
|
29284
|
-
case "R":
|
|
29285
|
-
return "renamed";
|
|
29286
|
-
default:
|
|
29287
|
-
return "modified";
|
|
29288
|
-
}
|
|
29289
|
-
}
|
|
29290
|
-
function categorizeCommit(message, body) {
|
|
29291
|
-
const text = `${message} ${body || ""}`.toLowerCase();
|
|
29292
|
-
if (text.includes("fix") || text.includes("bug") || text.includes("error") || text.includes("issue")) {
|
|
29293
|
-
return "error_fix";
|
|
29294
|
-
}
|
|
29295
|
-
if (text.includes("refactor") || text.includes("clean") || text.includes("simplify")) {
|
|
29296
|
-
return "refactor";
|
|
29297
|
-
}
|
|
29298
|
-
if (text.includes("workaround") || text.includes("hack") || text.includes("temporary")) {
|
|
29299
|
-
return "workaround";
|
|
29300
|
-
}
|
|
29301
|
-
if (text.includes("debug") || text.includes("log") || text.includes("trace")) {
|
|
29302
|
-
return "debugging";
|
|
29303
|
-
}
|
|
29304
|
-
return null;
|
|
29305
|
-
}
|
|
29306
|
-
function shouldSkipCommit(commit, ignorePatterns) {
|
|
29307
|
-
const message = commit.message.toLowerCase();
|
|
29308
|
-
for (const pattern of ignorePatterns) {
|
|
29309
|
-
if (message.includes(pattern.toLowerCase())) {
|
|
29310
|
-
return true;
|
|
29311
|
-
}
|
|
29312
|
-
}
|
|
29313
|
-
if (message.startsWith("merge ") || message.startsWith("wip")) {
|
|
29314
|
-
return true;
|
|
29315
|
-
}
|
|
29316
|
-
if (commit.files.length === 0) {
|
|
29317
|
-
return true;
|
|
29887
|
+
capitalize(str) {
|
|
29888
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
29318
29889
|
}
|
|
29319
|
-
|
|
29890
|
+
};
|
|
29891
|
+
function generatePrimer(projectPath, options = {}) {
|
|
29892
|
+
const generator = new PrimerGenerator(projectPath, options);
|
|
29893
|
+
return generator.generate();
|
|
29320
29894
|
}
|
|
29321
|
-
function
|
|
29322
|
-
|
|
29323
|
-
if (!category) return null;
|
|
29324
|
-
const id = `git-${commit.shortHash}`;
|
|
29325
|
-
const title = formatTitle(commit.message);
|
|
29326
|
-
const problem = extractProblem(commit);
|
|
29327
|
-
const solution = extractSolution(commit);
|
|
29328
|
-
const context = extractContext(commit);
|
|
29329
|
-
if (!problem || !solution) return null;
|
|
29330
|
-
return {
|
|
29331
|
-
id,
|
|
29332
|
-
category,
|
|
29333
|
-
title,
|
|
29334
|
-
problem,
|
|
29335
|
-
solution,
|
|
29336
|
-
context,
|
|
29337
|
-
extractedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
29338
|
-
source: "git",
|
|
29339
|
-
commitRange: { from: commit.hash, to: commit.hash },
|
|
29340
|
-
approved: false,
|
|
29341
|
-
confidence: calculateConfidence(commit, category)
|
|
29342
|
-
};
|
|
29895
|
+
function generatePrimerForAgent(projectPath, agent, options = {}) {
|
|
29896
|
+
return generatePrimer(projectPath, { ...options, agents: [agent] });
|
|
29343
29897
|
}
|
|
29344
|
-
function
|
|
29345
|
-
|
|
29898
|
+
function analyzeForPrimer(projectPath) {
|
|
29899
|
+
const generator = new PrimerGenerator(projectPath, { analyzeOnly: true });
|
|
29900
|
+
const result = generator.generate();
|
|
29901
|
+
return result.analysis;
|
|
29346
29902
|
}
|
|
29347
|
-
|
|
29348
|
-
|
|
29349
|
-
|
|
29350
|
-
|
|
29351
|
-
|
|
29352
|
-
|
|
29353
|
-
|
|
29354
|
-
|
|
29355
|
-
|
|
29356
|
-
|
|
29357
|
-
|
|
29358
|
-
|
|
29359
|
-
|
|
29360
|
-
|
|
29361
|
-
|
|
29903
|
+
|
|
29904
|
+
// src/learning/types.ts
|
|
29905
|
+
var DEFAULT_LEARNING_CONFIG = {
|
|
29906
|
+
minSessionLength: 10,
|
|
29907
|
+
sensitivity: "medium",
|
|
29908
|
+
autoApprove: false,
|
|
29909
|
+
outputPath: "~/.skillkit/learned/",
|
|
29910
|
+
categories: ["error_fix", "refactor", "workaround", "debugging", "convention"],
|
|
29911
|
+
ignorePatterns: ["trivial_typo", "one_off_fix", "wip", "merge"]
|
|
29912
|
+
};
|
|
29913
|
+
|
|
29914
|
+
// src/learning/config.ts
|
|
29915
|
+
import { existsSync as existsSync47, readFileSync as readFileSync34, writeFileSync as writeFileSync25, mkdirSync as mkdirSync25 } from "fs";
|
|
29916
|
+
import { join as join48, dirname as dirname16 } from "path";
|
|
29917
|
+
import { homedir as homedir14 } from "os";
|
|
29918
|
+
import yaml from "yaml";
|
|
29919
|
+
function getDefaultConfigPath() {
|
|
29920
|
+
return join48(homedir14(), ".skillkit", "learning.yaml");
|
|
29362
29921
|
}
|
|
29363
|
-
function
|
|
29364
|
-
|
|
29365
|
-
const solutionMatch = commit.body.match(/solution:?\s*(.+)/i);
|
|
29366
|
-
if (solutionMatch) {
|
|
29367
|
-
return solutionMatch[1].trim();
|
|
29368
|
-
}
|
|
29369
|
-
}
|
|
29370
|
-
const files = commit.files.map((f) => f.path).join(", ");
|
|
29371
|
-
return `Modified: ${files}`;
|
|
29922
|
+
function getDefaultStorePath() {
|
|
29923
|
+
return join48(homedir14(), ".skillkit", "learned", "patterns.json");
|
|
29372
29924
|
}
|
|
29373
|
-
function
|
|
29374
|
-
const
|
|
29375
|
-
|
|
29376
|
-
|
|
29377
|
-
const parts = [];
|
|
29378
|
-
if (extensions.size > 0) {
|
|
29379
|
-
parts.push(`Files: ${Array.from(extensions).filter((e) => e).join(", ")}`);
|
|
29925
|
+
function loadLearningConfig(configPath) {
|
|
29926
|
+
const path4 = configPath || getDefaultConfigPath();
|
|
29927
|
+
if (!existsSync47(path4)) {
|
|
29928
|
+
return DEFAULT_LEARNING_CONFIG;
|
|
29380
29929
|
}
|
|
29381
|
-
|
|
29382
|
-
|
|
29930
|
+
try {
|
|
29931
|
+
const content = readFileSync34(path4, "utf-8");
|
|
29932
|
+
const config = yaml.parse(content);
|
|
29933
|
+
return { ...DEFAULT_LEARNING_CONFIG, ...config };
|
|
29934
|
+
} catch {
|
|
29935
|
+
return DEFAULT_LEARNING_CONFIG;
|
|
29383
29936
|
}
|
|
29384
|
-
return parts.join(". ") || "General codebase";
|
|
29385
29937
|
}
|
|
29386
|
-
function
|
|
29387
|
-
|
|
29388
|
-
|
|
29389
|
-
|
|
29938
|
+
function saveLearningConfig(config, configPath) {
|
|
29939
|
+
const path4 = configPath || getDefaultConfigPath();
|
|
29940
|
+
const dir = dirname16(path4);
|
|
29941
|
+
if (!existsSync47(dir)) {
|
|
29942
|
+
mkdirSync25(dir, { recursive: true });
|
|
29390
29943
|
}
|
|
29391
|
-
|
|
29392
|
-
|
|
29944
|
+
const content = yaml.stringify(config);
|
|
29945
|
+
writeFileSync25(path4, content);
|
|
29946
|
+
}
|
|
29947
|
+
function loadPatternStore(storePath) {
|
|
29948
|
+
const path4 = storePath || getDefaultStorePath();
|
|
29949
|
+
if (!existsSync47(path4)) {
|
|
29950
|
+
return {
|
|
29951
|
+
version: 1,
|
|
29952
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
29953
|
+
patterns: [],
|
|
29954
|
+
evolvingPatterns: []
|
|
29955
|
+
};
|
|
29393
29956
|
}
|
|
29394
|
-
|
|
29395
|
-
|
|
29957
|
+
try {
|
|
29958
|
+
const content = readFileSync34(path4, "utf-8");
|
|
29959
|
+
return JSON.parse(content);
|
|
29960
|
+
} catch {
|
|
29961
|
+
return {
|
|
29962
|
+
version: 1,
|
|
29963
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
29964
|
+
patterns: [],
|
|
29965
|
+
evolvingPatterns: []
|
|
29966
|
+
};
|
|
29396
29967
|
}
|
|
29397
|
-
|
|
29398
|
-
|
|
29968
|
+
}
|
|
29969
|
+
function savePatternStore(store, storePath) {
|
|
29970
|
+
const path4 = storePath || getDefaultStorePath();
|
|
29971
|
+
const dir = dirname16(path4);
|
|
29972
|
+
if (!existsSync47(dir)) {
|
|
29973
|
+
mkdirSync25(dir, { recursive: true });
|
|
29399
29974
|
}
|
|
29400
|
-
|
|
29975
|
+
store.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
29976
|
+
const content = JSON.stringify(store, null, 2);
|
|
29977
|
+
writeFileSync25(path4, content);
|
|
29401
29978
|
}
|
|
29402
|
-
function
|
|
29403
|
-
const
|
|
29404
|
-
const
|
|
29405
|
-
|
|
29406
|
-
|
|
29407
|
-
|
|
29408
|
-
|
|
29409
|
-
errorFixes: 0,
|
|
29410
|
-
refactors: 0,
|
|
29411
|
-
features: 0,
|
|
29412
|
-
documentation: 0,
|
|
29413
|
-
tests: 0
|
|
29414
|
-
};
|
|
29415
|
-
const languages = /* @__PURE__ */ new Set();
|
|
29416
|
-
const frameworks = /* @__PURE__ */ new Set();
|
|
29417
|
-
for (const commit of commits) {
|
|
29418
|
-
if (shouldSkipCommit(commit, ignorePatterns)) {
|
|
29419
|
-
continue;
|
|
29420
|
-
}
|
|
29421
|
-
summary.totalFilesChanged += commit.files.length;
|
|
29422
|
-
for (const file of commit.files) {
|
|
29423
|
-
const ext = file.path.split(".").pop()?.toLowerCase();
|
|
29424
|
-
if (ext) {
|
|
29425
|
-
if (["ts", "tsx"].includes(ext)) languages.add("TypeScript");
|
|
29426
|
-
else if (["js", "jsx"].includes(ext)) languages.add("JavaScript");
|
|
29427
|
-
else if (ext === "py") languages.add("Python");
|
|
29428
|
-
else if (ext === "go") languages.add("Go");
|
|
29429
|
-
else if (ext === "rs") languages.add("Rust");
|
|
29430
|
-
else if (ext === "java") languages.add("Java");
|
|
29431
|
-
}
|
|
29432
|
-
if (file.path.includes("next")) frameworks.add("Next.js");
|
|
29433
|
-
if (file.path.includes("react")) frameworks.add("React");
|
|
29434
|
-
if (file.path.includes("vue")) frameworks.add("Vue");
|
|
29435
|
-
}
|
|
29436
|
-
const category = categorizeCommit(commit.message, commit.body);
|
|
29437
|
-
if (category === "error_fix") summary.errorFixes++;
|
|
29438
|
-
else if (category === "refactor") summary.refactors++;
|
|
29439
|
-
if (commit.message.toLowerCase().includes("feat")) summary.features++;
|
|
29440
|
-
if (commit.message.toLowerCase().includes("doc")) summary.documentation++;
|
|
29441
|
-
if (commit.message.toLowerCase().includes("test")) summary.tests++;
|
|
29442
|
-
const pattern = extractPatternFromCommit(commit);
|
|
29443
|
-
if (pattern) {
|
|
29444
|
-
patterns.push(pattern);
|
|
29445
|
-
}
|
|
29979
|
+
function addPattern(pattern, storePath) {
|
|
29980
|
+
const store = loadPatternStore(storePath);
|
|
29981
|
+
const existingIndex = store.patterns.findIndex((p) => p.id === pattern.id);
|
|
29982
|
+
if (existingIndex >= 0) {
|
|
29983
|
+
store.patterns[existingIndex] = pattern;
|
|
29984
|
+
} else {
|
|
29985
|
+
store.patterns.push(pattern);
|
|
29446
29986
|
}
|
|
29447
|
-
|
|
29448
|
-
return
|
|
29449
|
-
patterns,
|
|
29450
|
-
commitCount: commits.length,
|
|
29451
|
-
dateRange: {
|
|
29452
|
-
from: dates[0] || "",
|
|
29453
|
-
to: dates[dates.length - 1] || ""
|
|
29454
|
-
},
|
|
29455
|
-
languages: Array.from(languages),
|
|
29456
|
-
frameworks: Array.from(frameworks),
|
|
29457
|
-
summary
|
|
29458
|
-
};
|
|
29987
|
+
savePatternStore(store, storePath);
|
|
29988
|
+
return store;
|
|
29459
29989
|
}
|
|
29460
|
-
function
|
|
29461
|
-
const
|
|
29462
|
-
|
|
29990
|
+
function removePattern(patternId, storePath) {
|
|
29991
|
+
const store = loadPatternStore(storePath);
|
|
29992
|
+
store.patterns = store.patterns.filter((p) => p.id !== patternId);
|
|
29993
|
+
store.evolvingPatterns = store.evolvingPatterns.filter((p) => p.id !== patternId);
|
|
29994
|
+
savePatternStore(store, storePath);
|
|
29995
|
+
return store;
|
|
29463
29996
|
}
|
|
29464
|
-
function
|
|
29465
|
-
const
|
|
29466
|
-
return
|
|
29997
|
+
function getPattern(patternId, storePath) {
|
|
29998
|
+
const store = loadPatternStore(storePath);
|
|
29999
|
+
return store.patterns.find((p) => p.id === patternId) || null;
|
|
30000
|
+
}
|
|
30001
|
+
function getEvolvingPattern(patternId, storePath) {
|
|
30002
|
+
const store = loadPatternStore(storePath);
|
|
30003
|
+
return store.evolvingPatterns.find((p) => p.id === patternId) || null;
|
|
30004
|
+
}
|
|
30005
|
+
function getAllPatterns(storePath) {
|
|
30006
|
+
const store = loadPatternStore(storePath);
|
|
30007
|
+
return store.patterns;
|
|
30008
|
+
}
|
|
30009
|
+
function getPatternsByCategory(category, storePath) {
|
|
30010
|
+
const store = loadPatternStore(storePath);
|
|
30011
|
+
return store.patterns.filter((p) => p.category === category);
|
|
30012
|
+
}
|
|
30013
|
+
function getApprovedPatterns(storePath) {
|
|
30014
|
+
const store = loadPatternStore(storePath);
|
|
30015
|
+
return store.patterns.filter((p) => p.approved);
|
|
29467
30016
|
}
|
|
29468
30017
|
|
|
29469
30018
|
// src/learning/extractor.ts
|
|
@@ -29716,8 +30265,8 @@ function mergePatterns(existing, newPatterns) {
|
|
|
29716
30265
|
}
|
|
29717
30266
|
|
|
29718
30267
|
// src/learning/generator.ts
|
|
29719
|
-
import { writeFileSync as
|
|
29720
|
-
import { join as
|
|
30268
|
+
import { writeFileSync as writeFileSync26, mkdirSync as mkdirSync26, existsSync as existsSync48 } from "fs";
|
|
30269
|
+
import { join as join49 } from "path";
|
|
29721
30270
|
import { homedir as homedir15 } from "os";
|
|
29722
30271
|
function generateSkillFromPatterns(patterns, options = {}) {
|
|
29723
30272
|
const minConfidence = options.minConfidence ?? 0.5;
|
|
@@ -29808,12 +30357,12 @@ function generateSkillContent2(name, patterns, category) {
|
|
|
29808
30357
|
return lines.join("\n");
|
|
29809
30358
|
}
|
|
29810
30359
|
function saveGeneratedSkill(skill, outputDir) {
|
|
29811
|
-
const dir = outputDir ||
|
|
29812
|
-
if (!
|
|
29813
|
-
|
|
30360
|
+
const dir = outputDir || join49(homedir15(), ".skillkit", "skills", "learned");
|
|
30361
|
+
if (!existsSync48(dir)) {
|
|
30362
|
+
mkdirSync26(dir, { recursive: true });
|
|
29814
30363
|
}
|
|
29815
|
-
const filepath =
|
|
29816
|
-
|
|
30364
|
+
const filepath = join49(dir, skill.filename);
|
|
30365
|
+
writeFileSync26(filepath, skill.content);
|
|
29817
30366
|
return filepath;
|
|
29818
30367
|
}
|
|
29819
30368
|
function generatePatternReport(patterns) {
|
|
@@ -30043,8 +30592,8 @@ var DEFAULT_PROFILE_CONFIG = {
|
|
|
30043
30592
|
};
|
|
30044
30593
|
|
|
30045
30594
|
// src/profiles/manager.ts
|
|
30046
|
-
import { existsSync as
|
|
30047
|
-
import { join as
|
|
30595
|
+
import { existsSync as existsSync49, readFileSync as readFileSync35, writeFileSync as writeFileSync27, mkdirSync as mkdirSync27 } from "fs";
|
|
30596
|
+
import { join as join50, dirname as dirname17 } from "path";
|
|
30048
30597
|
import { homedir as homedir16 } from "os";
|
|
30049
30598
|
import yaml2 from "yaml";
|
|
30050
30599
|
var BUILTIN_PROFILES = [
|
|
@@ -30125,15 +30674,15 @@ var BUILTIN_PROFILES = [
|
|
|
30125
30674
|
}
|
|
30126
30675
|
];
|
|
30127
30676
|
function getConfigPath() {
|
|
30128
|
-
return
|
|
30677
|
+
return join50(homedir16(), ".skillkit", "profiles.yaml");
|
|
30129
30678
|
}
|
|
30130
30679
|
function loadProfileConfig() {
|
|
30131
30680
|
const path4 = getConfigPath();
|
|
30132
|
-
if (!
|
|
30681
|
+
if (!existsSync49(path4)) {
|
|
30133
30682
|
return DEFAULT_PROFILE_CONFIG;
|
|
30134
30683
|
}
|
|
30135
30684
|
try {
|
|
30136
|
-
const content =
|
|
30685
|
+
const content = readFileSync35(path4, "utf-8");
|
|
30137
30686
|
return { ...DEFAULT_PROFILE_CONFIG, ...yaml2.parse(content) };
|
|
30138
30687
|
} catch {
|
|
30139
30688
|
return DEFAULT_PROFILE_CONFIG;
|
|
@@ -30142,10 +30691,10 @@ function loadProfileConfig() {
|
|
|
30142
30691
|
function saveProfileConfig(config) {
|
|
30143
30692
|
const path4 = getConfigPath();
|
|
30144
30693
|
const dir = dirname17(path4);
|
|
30145
|
-
if (!
|
|
30146
|
-
|
|
30694
|
+
if (!existsSync49(dir)) {
|
|
30695
|
+
mkdirSync27(dir, { recursive: true });
|
|
30147
30696
|
}
|
|
30148
|
-
|
|
30697
|
+
writeFileSync27(path4, yaml2.stringify(config));
|
|
30149
30698
|
}
|
|
30150
30699
|
function getActiveProfile() {
|
|
30151
30700
|
const config = loadProfileConfig();
|
|
@@ -30212,8 +30761,8 @@ var DEFAULT_GUIDELINE_CONFIG = {
|
|
|
30212
30761
|
};
|
|
30213
30762
|
|
|
30214
30763
|
// src/guidelines/manager.ts
|
|
30215
|
-
import { existsSync as
|
|
30216
|
-
import { join as
|
|
30764
|
+
import { existsSync as existsSync50, readFileSync as readFileSync36, writeFileSync as writeFileSync28, mkdirSync as mkdirSync28 } from "fs";
|
|
30765
|
+
import { join as join51, dirname as dirname18 } from "path";
|
|
30217
30766
|
import { homedir as homedir17 } from "os";
|
|
30218
30767
|
import yaml3 from "yaml";
|
|
30219
30768
|
var BUILTIN_GUIDELINES = [
|
|
@@ -30391,15 +30940,15 @@ Types: feat, fix, docs, style, refactor, test, chore`
|
|
|
30391
30940
|
}
|
|
30392
30941
|
];
|
|
30393
30942
|
function getConfigPath2() {
|
|
30394
|
-
return
|
|
30943
|
+
return join51(homedir17(), ".skillkit", "guidelines.yaml");
|
|
30395
30944
|
}
|
|
30396
30945
|
function loadGuidelineConfig() {
|
|
30397
30946
|
const path4 = getConfigPath2();
|
|
30398
|
-
if (!
|
|
30947
|
+
if (!existsSync50(path4)) {
|
|
30399
30948
|
return DEFAULT_GUIDELINE_CONFIG;
|
|
30400
30949
|
}
|
|
30401
30950
|
try {
|
|
30402
|
-
const content =
|
|
30951
|
+
const content = readFileSync36(path4, "utf-8");
|
|
30403
30952
|
return { ...DEFAULT_GUIDELINE_CONFIG, ...yaml3.parse(content) };
|
|
30404
30953
|
} catch {
|
|
30405
30954
|
return DEFAULT_GUIDELINE_CONFIG;
|
|
@@ -30408,10 +30957,10 @@ function loadGuidelineConfig() {
|
|
|
30408
30957
|
function saveGuidelineConfig(config) {
|
|
30409
30958
|
const path4 = getConfigPath2();
|
|
30410
30959
|
const dir = dirname18(path4);
|
|
30411
|
-
if (!
|
|
30412
|
-
|
|
30960
|
+
if (!existsSync50(dir)) {
|
|
30961
|
+
mkdirSync28(dir, { recursive: true });
|
|
30413
30962
|
}
|
|
30414
|
-
|
|
30963
|
+
writeFileSync28(path4, yaml3.stringify(config));
|
|
30415
30964
|
}
|
|
30416
30965
|
function getGuideline(id) {
|
|
30417
30966
|
const builtin = BUILTIN_GUIDELINES.find((g) => g.id === id);
|
|
@@ -30493,7 +31042,7 @@ init_generator();
|
|
|
30493
31042
|
|
|
30494
31043
|
// src/tree/serializer.ts
|
|
30495
31044
|
init_types3();
|
|
30496
|
-
import { readFileSync as
|
|
31045
|
+
import { readFileSync as readFileSync37, writeFileSync as writeFileSync29, existsSync as existsSync51, mkdirSync as mkdirSync29 } from "fs";
|
|
30497
31046
|
import { dirname as dirname19 } from "path";
|
|
30498
31047
|
var TREE_FILE_NAME = "skill-tree.json";
|
|
30499
31048
|
function serializeTree(tree) {
|
|
@@ -30505,18 +31054,18 @@ function deserializeTree(json) {
|
|
|
30505
31054
|
}
|
|
30506
31055
|
function saveTree(tree, path4) {
|
|
30507
31056
|
const dir = dirname19(path4);
|
|
30508
|
-
if (!
|
|
30509
|
-
|
|
31057
|
+
if (!existsSync51(dir)) {
|
|
31058
|
+
mkdirSync29(dir, { recursive: true });
|
|
30510
31059
|
}
|
|
30511
31060
|
const json = serializeTree(tree);
|
|
30512
|
-
|
|
31061
|
+
writeFileSync29(path4, json, "utf-8");
|
|
30513
31062
|
}
|
|
30514
31063
|
function loadTree(path4) {
|
|
30515
|
-
if (!
|
|
31064
|
+
if (!existsSync51(path4)) {
|
|
30516
31065
|
return null;
|
|
30517
31066
|
}
|
|
30518
31067
|
try {
|
|
30519
|
-
const json =
|
|
31068
|
+
const json = readFileSync37(path4, "utf-8");
|
|
30520
31069
|
return deserializeTree(json);
|
|
30521
31070
|
} catch {
|
|
30522
31071
|
return null;
|
|
@@ -31471,12 +32020,12 @@ function createExecutionManager(config) {
|
|
|
31471
32020
|
}
|
|
31472
32021
|
|
|
31473
32022
|
// src/execution/mode.ts
|
|
31474
|
-
import { existsSync as
|
|
31475
|
-
import { join as
|
|
32023
|
+
import { existsSync as existsSync52, readFileSync as readFileSync38 } from "fs";
|
|
32024
|
+
import { join as join52 } from "path";
|
|
31476
32025
|
import { homedir as homedir18 } from "os";
|
|
31477
32026
|
var DEFAULT_MCP_CONFIG_PATHS = [
|
|
31478
|
-
|
|
31479
|
-
|
|
32027
|
+
join52(homedir18(), ".mcp.json"),
|
|
32028
|
+
join52(homedir18(), ".config", "claude", "mcp.json"),
|
|
31480
32029
|
".mcp.json",
|
|
31481
32030
|
"mcp.json"
|
|
31482
32031
|
];
|
|
@@ -31525,8 +32074,8 @@ function detectMcpServers(configPaths) {
|
|
|
31525
32074
|
for (const configPath of configPaths) {
|
|
31526
32075
|
try {
|
|
31527
32076
|
const fullPath = configPath.startsWith("~") ? configPath.replace("~", process.env.HOME || "") : configPath;
|
|
31528
|
-
if (
|
|
31529
|
-
const content =
|
|
32077
|
+
if (existsSync52(fullPath)) {
|
|
32078
|
+
const content = readFileSync38(fullPath, "utf-8");
|
|
31530
32079
|
const config = JSON.parse(content);
|
|
31531
32080
|
if (config.mcpServers) {
|
|
31532
32081
|
servers.push(...Object.keys(config.mcpServers));
|
|
@@ -31664,8 +32213,8 @@ init_expansion();
|
|
|
31664
32213
|
init_hybrid();
|
|
31665
32214
|
|
|
31666
32215
|
// src/registry/community.ts
|
|
31667
|
-
import { readFileSync as
|
|
31668
|
-
import { join as
|
|
32216
|
+
import { readFileSync as readFileSync39, existsSync as existsSync53 } from "fs";
|
|
32217
|
+
import { join as join53, dirname as dirname20 } from "path";
|
|
31669
32218
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
31670
32219
|
var CommunityRegistry = class {
|
|
31671
32220
|
constructor(skillsMdPath) {
|
|
@@ -31678,13 +32227,13 @@ var CommunityRegistry = class {
|
|
|
31678
32227
|
if (this.loaded) return;
|
|
31679
32228
|
this.loaded = true;
|
|
31680
32229
|
const paths = this.skillsMdPath ? [this.skillsMdPath] : [
|
|
31681
|
-
|
|
31682
|
-
|
|
32230
|
+
join53(process.cwd(), "registry", "SKILLS.md"),
|
|
32231
|
+
join53(dirname20(fileURLToPath2(import.meta.url)), "..", "..", "..", "..", "registry", "SKILLS.md")
|
|
31683
32232
|
];
|
|
31684
32233
|
for (const path4 of paths) {
|
|
31685
|
-
if (!
|
|
32234
|
+
if (!existsSync53(path4)) continue;
|
|
31686
32235
|
try {
|
|
31687
|
-
const content =
|
|
32236
|
+
const content = readFileSync39(path4, "utf-8");
|
|
31688
32237
|
this.entries = this.parse(content);
|
|
31689
32238
|
return;
|
|
31690
32239
|
} catch {
|
|
@@ -31983,8 +32532,8 @@ var RelevanceRanker = class {
|
|
|
31983
32532
|
};
|
|
31984
32533
|
|
|
31985
32534
|
// src/parser/references.ts
|
|
31986
|
-
import { readdirSync as
|
|
31987
|
-
import { join as
|
|
32535
|
+
import { readdirSync as readdirSync14, statSync as statSync10, existsSync as existsSync54 } from "fs";
|
|
32536
|
+
import { join as join54 } from "path";
|
|
31988
32537
|
var REFERENCE_DIRS = ["references", "resources", "docs", "examples", "assets", "scripts"];
|
|
31989
32538
|
var DIR_TYPE_MAP = {
|
|
31990
32539
|
references: "resource",
|
|
@@ -31997,8 +32546,8 @@ var DIR_TYPE_MAP = {
|
|
|
31997
32546
|
function discoverReferences(skillDir) {
|
|
31998
32547
|
const refs = [];
|
|
31999
32548
|
for (const dir of REFERENCE_DIRS) {
|
|
32000
|
-
const fullPath =
|
|
32001
|
-
if (!
|
|
32549
|
+
const fullPath = join54(skillDir, dir);
|
|
32550
|
+
if (!existsSync54(fullPath)) continue;
|
|
32002
32551
|
try {
|
|
32003
32552
|
const stat = statSync10(fullPath);
|
|
32004
32553
|
if (!stat.isDirectory()) continue;
|
|
@@ -32007,14 +32556,14 @@ function discoverReferences(skillDir) {
|
|
|
32007
32556
|
}
|
|
32008
32557
|
const type = DIR_TYPE_MAP[dir] || "resource";
|
|
32009
32558
|
try {
|
|
32010
|
-
const entries =
|
|
32559
|
+
const entries = readdirSync14(fullPath);
|
|
32011
32560
|
for (const entry of entries) {
|
|
32012
|
-
const entryPath =
|
|
32561
|
+
const entryPath = join54(fullPath, entry);
|
|
32013
32562
|
try {
|
|
32014
32563
|
const entryStat = statSync10(entryPath);
|
|
32015
32564
|
if (entryStat.isFile()) {
|
|
32016
32565
|
refs.push({
|
|
32017
|
-
path:
|
|
32566
|
+
path: join54(dir, entry),
|
|
32018
32567
|
type,
|
|
32019
32568
|
name: entry
|
|
32020
32569
|
});
|
|
@@ -33181,7 +33730,7 @@ var SecretsAnalyzer = class {
|
|
|
33181
33730
|
|
|
33182
33731
|
// src/scanner/scanner.ts
|
|
33183
33732
|
import { readdir } from "fs/promises";
|
|
33184
|
-
import { join as
|
|
33733
|
+
import { join as join55, basename as basename20 } from "path";
|
|
33185
33734
|
var SEVERITY_ORDER = {
|
|
33186
33735
|
["critical" /* CRITICAL */]: 5,
|
|
33187
33736
|
["high" /* HIGH */]: 4,
|
|
@@ -33200,7 +33749,7 @@ async function discoverFiles(dirPath) {
|
|
|
33200
33749
|
return;
|
|
33201
33750
|
}
|
|
33202
33751
|
for (const entry of entries) {
|
|
33203
|
-
const fullPath =
|
|
33752
|
+
const fullPath = join55(dir, entry.name);
|
|
33204
33753
|
if (entry.name.startsWith(".") && entry.name !== ".env" && !entry.name.startsWith(".env.")) continue;
|
|
33205
33754
|
if (entry.name === "node_modules") continue;
|
|
33206
33755
|
if (entry.isDirectory()) {
|
|
@@ -33294,7 +33843,7 @@ var SkillScanner = class {
|
|
|
33294
33843
|
|
|
33295
33844
|
// src/scanner/reporter.ts
|
|
33296
33845
|
import { basename as basename21 } from "path";
|
|
33297
|
-
var SCANNER_VERSION = true ? "1.
|
|
33846
|
+
var SCANNER_VERSION = true ? "1.18.0" : "0.0.0";
|
|
33298
33847
|
var SEVERITY_COLORS = {
|
|
33299
33848
|
["critical" /* CRITICAL */]: "\x1B[91m",
|
|
33300
33849
|
["high" /* HIGH */]: "\x1B[31m",
|
|
@@ -33567,8 +34116,8 @@ function getDefaultSeverity(category) {
|
|
|
33567
34116
|
}
|
|
33568
34117
|
|
|
33569
34118
|
// src/validation/spec-validator.ts
|
|
33570
|
-
import { readFileSync as
|
|
33571
|
-
import { join as
|
|
34119
|
+
import { readFileSync as readFileSync40, existsSync as existsSync55 } from "fs";
|
|
34120
|
+
import { join as join56, basename as basename22 } from "path";
|
|
33572
34121
|
var NAME_PATTERN = /^[a-z0-9]+(-[a-z0-9]+)*$/;
|
|
33573
34122
|
var SPEC_VERSION = "1.0";
|
|
33574
34123
|
var SpecValidator = class {
|
|
@@ -33576,12 +34125,12 @@ var SpecValidator = class {
|
|
|
33576
34125
|
const checks = [];
|
|
33577
34126
|
const errors = [];
|
|
33578
34127
|
const warnings = [];
|
|
33579
|
-
const skillMdPath = skillPath.endsWith(".md") ? skillPath :
|
|
33580
|
-
if (!
|
|
34128
|
+
const skillMdPath = skillPath.endsWith(".md") ? skillPath : join56(skillPath, "SKILL.md");
|
|
34129
|
+
if (!existsSync55(skillMdPath)) {
|
|
33581
34130
|
errors.push(`SKILL.md not found at ${skillMdPath}`);
|
|
33582
34131
|
return { valid: false, errors, warnings, specVersion: SPEC_VERSION, checks };
|
|
33583
34132
|
}
|
|
33584
|
-
const raw =
|
|
34133
|
+
const raw = readFileSync40(skillMdPath, "utf-8");
|
|
33585
34134
|
const { frontmatter, body } = stripFrontmatter(raw);
|
|
33586
34135
|
const hasName = typeof frontmatter.name === "string" && frontmatter.name.length > 0;
|
|
33587
34136
|
checks.push({
|
|
@@ -33648,7 +34197,7 @@ var SpecValidator = class {
|
|
|
33648
34197
|
});
|
|
33649
34198
|
}
|
|
33650
34199
|
if (hasName) {
|
|
33651
|
-
const skillDir = skillPath.endsWith(".md") ?
|
|
34200
|
+
const skillDir = skillPath.endsWith(".md") ? join56(skillPath, "..") : skillPath;
|
|
33652
34201
|
const dirName = basename22(skillDir);
|
|
33653
34202
|
const nameStr = frontmatter.name;
|
|
33654
34203
|
const nameMatchesDir = nameStr === dirName;
|
|
@@ -33681,8 +34230,8 @@ var SpecValidator = class {
|
|
|
33681
34230
|
};
|
|
33682
34231
|
|
|
33683
34232
|
// src/agents-md/generator.ts
|
|
33684
|
-
import { existsSync as
|
|
33685
|
-
import { join as
|
|
34233
|
+
import { existsSync as existsSync56, readFileSync as readFileSync41 } from "fs";
|
|
34234
|
+
import { join as join57 } from "path";
|
|
33686
34235
|
function escapeTableCell(text) {
|
|
33687
34236
|
return text.replace(/\|/g, "\\|").replace(/\n/g, " ");
|
|
33688
34237
|
}
|
|
@@ -33711,7 +34260,7 @@ var AgentsMdGenerator = class {
|
|
|
33711
34260
|
managed: true
|
|
33712
34261
|
});
|
|
33713
34262
|
if (this.config.includeSkills !== false) {
|
|
33714
|
-
const skillsContent = this.generateSkillsSection(findAllSkills([
|
|
34263
|
+
const skillsContent = this.generateSkillsSection(findAllSkills([join57(this.config.projectPath, "skills")]));
|
|
33715
34264
|
if (skillsContent) {
|
|
33716
34265
|
sections.push({
|
|
33717
34266
|
id: "installed-skills",
|
|
@@ -33754,7 +34303,7 @@ var AgentsMdGenerator = class {
|
|
|
33754
34303
|
return {
|
|
33755
34304
|
content,
|
|
33756
34305
|
sections,
|
|
33757
|
-
path:
|
|
34306
|
+
path: join57(this.config.projectPath, "AGENTS.md")
|
|
33758
34307
|
};
|
|
33759
34308
|
}
|
|
33760
34309
|
generateSkillsSection(skills) {
|
|
@@ -33785,12 +34334,12 @@ var AgentsMdGenerator = class {
|
|
|
33785
34334
|
return lines.join("\n");
|
|
33786
34335
|
}
|
|
33787
34336
|
generateBuildSection() {
|
|
33788
|
-
const packageJsonPath =
|
|
33789
|
-
if (!
|
|
34337
|
+
const packageJsonPath = join57(this.config.projectPath, "package.json");
|
|
34338
|
+
if (!existsSync56(packageJsonPath)) {
|
|
33790
34339
|
return "";
|
|
33791
34340
|
}
|
|
33792
34341
|
try {
|
|
33793
|
-
const pkg = JSON.parse(
|
|
34342
|
+
const pkg = JSON.parse(readFileSync41(packageJsonPath, "utf-8"));
|
|
33794
34343
|
const scripts = pkg.scripts;
|
|
33795
34344
|
if (!scripts || Object.keys(scripts).length === 0) {
|
|
33796
34345
|
return "";
|
|
@@ -33942,7 +34491,7 @@ var AgentsMdParser = class {
|
|
|
33942
34491
|
};
|
|
33943
34492
|
|
|
33944
34493
|
// src/save/extractor.ts
|
|
33945
|
-
import { existsSync as
|
|
34494
|
+
import { existsSync as existsSync57, readFileSync as readFileSync42 } from "fs";
|
|
33946
34495
|
import { basename as basename23, extname as extname7 } from "path";
|
|
33947
34496
|
import TurndownService from "turndown";
|
|
33948
34497
|
var LANGUAGE_MAP = {
|
|
@@ -34044,10 +34593,10 @@ var ContentExtractor = class {
|
|
|
34044
34593
|
};
|
|
34045
34594
|
}
|
|
34046
34595
|
extractFromFile(filePath, options) {
|
|
34047
|
-
if (!
|
|
34596
|
+
if (!existsSync57(filePath)) {
|
|
34048
34597
|
throw new Error(`File not found: ${filePath}`);
|
|
34049
34598
|
}
|
|
34050
|
-
const raw =
|
|
34599
|
+
const raw = readFileSync42(filePath, "utf-8");
|
|
34051
34600
|
const name = basename23(filePath);
|
|
34052
34601
|
const language = this.detectLanguage(name);
|
|
34053
34602
|
const isCode = language !== void 0 && language !== "markdown";
|
|
@@ -34247,8 +34796,8 @@ var AutoTagger = class {
|
|
|
34247
34796
|
};
|
|
34248
34797
|
|
|
34249
34798
|
// src/save/skill-generator.ts
|
|
34250
|
-
import { mkdirSync as
|
|
34251
|
-
import { join as
|
|
34799
|
+
import { mkdirSync as mkdirSync30, writeFileSync as writeFileSync30 } from "fs";
|
|
34800
|
+
import { join as join58 } from "path";
|
|
34252
34801
|
import { homedir as homedir19 } from "os";
|
|
34253
34802
|
var MAX_NAME_LENGTH = 64;
|
|
34254
34803
|
var SUMMARY_LINE_LIMIT = 100;
|
|
@@ -34269,14 +34818,14 @@ var SkillGenerator = class {
|
|
|
34269
34818
|
${body}
|
|
34270
34819
|
`;
|
|
34271
34820
|
const outputDir = options.outputDir ?? this.defaultOutputDir(name, options.global);
|
|
34272
|
-
|
|
34273
|
-
const skillPath =
|
|
34274
|
-
|
|
34821
|
+
mkdirSync30(outputDir, { recursive: true });
|
|
34822
|
+
const skillPath = join58(outputDir, "SKILL.md");
|
|
34823
|
+
writeFileSync30(skillPath, skillMd, "utf-8");
|
|
34275
34824
|
if (needsSplit) {
|
|
34276
|
-
const refsDir =
|
|
34277
|
-
|
|
34278
|
-
|
|
34279
|
-
|
|
34825
|
+
const refsDir = join58(outputDir, "references");
|
|
34826
|
+
mkdirSync30(refsDir, { recursive: true });
|
|
34827
|
+
writeFileSync30(
|
|
34828
|
+
join58(refsDir, "full-content.md"),
|
|
34280
34829
|
content.content,
|
|
34281
34830
|
"utf-8"
|
|
34282
34831
|
);
|
|
@@ -34318,9 +34867,9 @@ ${yamlTags}` : null,
|
|
|
34318
34867
|
}
|
|
34319
34868
|
defaultOutputDir(name, global) {
|
|
34320
34869
|
if (global) {
|
|
34321
|
-
return
|
|
34870
|
+
return join58(homedir19(), ".skillkit", "skills", name);
|
|
34322
34871
|
}
|
|
34323
|
-
return
|
|
34872
|
+
return join58(".skillkit", "skills", name);
|
|
34324
34873
|
}
|
|
34325
34874
|
};
|
|
34326
34875
|
export {
|
|
@@ -34335,6 +34884,7 @@ export {
|
|
|
34335
34884
|
AISkillGenerator,
|
|
34336
34885
|
ALL_AGENT_DISCOVERY_PATHS,
|
|
34337
34886
|
APIBasedCompressor,
|
|
34887
|
+
ActivityLog,
|
|
34338
34888
|
AgentFrontmatter,
|
|
34339
34889
|
AgentHook,
|
|
34340
34890
|
AgentLocation,
|
|
@@ -34406,6 +34956,7 @@ export {
|
|
|
34406
34956
|
INDEX_CACHE_HOURS,
|
|
34407
34957
|
INDEX_PATH,
|
|
34408
34958
|
InjectionDetector,
|
|
34959
|
+
IssuePlanner,
|
|
34409
34960
|
KNOWN_SKILL_REPOS,
|
|
34410
34961
|
LearningConsolidator,
|
|
34411
34962
|
LearningStore,
|
|
@@ -34462,6 +35013,7 @@ export {
|
|
|
34462
35013
|
STEP_HANDLERS,
|
|
34463
35014
|
SecretsAnalyzer,
|
|
34464
35015
|
SessionEndHook,
|
|
35016
|
+
SessionExplainer,
|
|
34465
35017
|
SessionManager,
|
|
34466
35018
|
SessionStartHook,
|
|
34467
35019
|
Severity,
|
|
@@ -34485,6 +35037,7 @@ export {
|
|
|
34485
35037
|
SkillWizard,
|
|
34486
35038
|
SkillkitConfig,
|
|
34487
35039
|
SkillsSource,
|
|
35040
|
+
SnapshotManager,
|
|
34488
35041
|
SpecValidator,
|
|
34489
35042
|
StaticAnalyzer,
|
|
34490
35043
|
TAG_TO_CATEGORY,
|
|
@@ -34548,6 +35101,7 @@ export {
|
|
|
34548
35101
|
createHookManager,
|
|
34549
35102
|
createHybridSearchPipeline,
|
|
34550
35103
|
createInitialState,
|
|
35104
|
+
createIssuePlanner,
|
|
34551
35105
|
createMarketplaceAggregator,
|
|
34552
35106
|
createMemoryCompressor,
|
|
34553
35107
|
createMemoryEnabledEngine,
|