@aman_asmuei/aman-agent 0.26.0 → 0.27.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/README.md +19 -11
- package/dist/index.js +588 -205
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1387,18 +1387,18 @@ var McpManager = class {
|
|
|
1387
1387
|
|
|
1388
1388
|
// src/agent.ts
|
|
1389
1389
|
import * as readline from "readline";
|
|
1390
|
-
import
|
|
1391
|
-
import
|
|
1392
|
-
import
|
|
1390
|
+
import fs20 from "fs";
|
|
1391
|
+
import path20 from "path";
|
|
1392
|
+
import os19 from "os";
|
|
1393
1393
|
import pc7 from "picocolors";
|
|
1394
1394
|
import { marked } from "marked";
|
|
1395
1395
|
import { markedTerminal } from "marked-terminal";
|
|
1396
1396
|
import logUpdate from "log-update";
|
|
1397
1397
|
|
|
1398
1398
|
// src/commands.ts
|
|
1399
|
-
import
|
|
1400
|
-
import
|
|
1401
|
-
import
|
|
1399
|
+
import fs17 from "fs";
|
|
1400
|
+
import path17 from "path";
|
|
1401
|
+
import os16 from "os";
|
|
1402
1402
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
1403
1403
|
import pc5 from "picocolors";
|
|
1404
1404
|
|
|
@@ -2361,9 +2361,9 @@ import pc3 from "picocolors";
|
|
|
2361
2361
|
// src/hooks.ts
|
|
2362
2362
|
import pc2 from "picocolors";
|
|
2363
2363
|
import * as p2 from "@clack/prompts";
|
|
2364
|
-
import
|
|
2365
|
-
import
|
|
2366
|
-
import
|
|
2364
|
+
import fs14 from "fs";
|
|
2365
|
+
import path14 from "path";
|
|
2366
|
+
import os13 from "os";
|
|
2367
2367
|
|
|
2368
2368
|
// src/personality.ts
|
|
2369
2369
|
var FRUSTRATION_SIGNALS = [
|
|
@@ -2524,13 +2524,19 @@ function formatWellbeingNudge(state) {
|
|
|
2524
2524
|
if (!state.wellbeingNudge) return null;
|
|
2525
2525
|
return WELLBEING_NUDGES[state.wellbeingNudge] || null;
|
|
2526
2526
|
}
|
|
2527
|
-
async function syncPersonalityToCore(state, mcpManager) {
|
|
2527
|
+
async function syncPersonalityToCore(state, mcpManager, modelMetrics) {
|
|
2528
2528
|
try {
|
|
2529
|
-
|
|
2529
|
+
const payload = {
|
|
2530
2530
|
currentRead: state.currentRead,
|
|
2531
2531
|
energy: state.energy,
|
|
2532
2532
|
activeMode: state.activeMode
|
|
2533
|
-
}
|
|
2533
|
+
};
|
|
2534
|
+
if (modelMetrics) {
|
|
2535
|
+
payload.trust = `${(modelMetrics.trustScore * 100).toFixed(0)}%`;
|
|
2536
|
+
payload.sessions = modelMetrics.totalSessions;
|
|
2537
|
+
payload.sentimentTrend = modelMetrics.sentimentTrend;
|
|
2538
|
+
}
|
|
2539
|
+
await mcpManager.callTool("identity_update_dynamics", payload);
|
|
2534
2540
|
} catch (err) {
|
|
2535
2541
|
log.debug("personality", "identity_update_dynamics failed", err);
|
|
2536
2542
|
}
|
|
@@ -3200,6 +3206,258 @@ async function appendRejection(candidate, postmortemFilename, rejectionsPath) {
|
|
|
3200
3206
|
}
|
|
3201
3207
|
}
|
|
3202
3208
|
|
|
3209
|
+
// src/user-model.ts
|
|
3210
|
+
import fs13 from "fs/promises";
|
|
3211
|
+
import path13 from "path";
|
|
3212
|
+
import os12 from "os";
|
|
3213
|
+
var MAX_SESSIONS = 30;
|
|
3214
|
+
var TRUST_ALPHA = 0.3;
|
|
3215
|
+
var MIN_SESSIONS_FOR_FEED_FORWARD = 5;
|
|
3216
|
+
var MIN_SESSIONS_FOR_CORRELATIONS = 10;
|
|
3217
|
+
function defaultModelPath() {
|
|
3218
|
+
return path13.join(os12.homedir(), ".acore", "user-model.json");
|
|
3219
|
+
}
|
|
3220
|
+
function createEmptyModel() {
|
|
3221
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
3222
|
+
return {
|
|
3223
|
+
version: 1,
|
|
3224
|
+
sessions: [],
|
|
3225
|
+
profile: emptyProfile(),
|
|
3226
|
+
createdAt: now,
|
|
3227
|
+
updatedAt: now
|
|
3228
|
+
};
|
|
3229
|
+
}
|
|
3230
|
+
function emptyProfile() {
|
|
3231
|
+
return {
|
|
3232
|
+
trustScore: 0.5,
|
|
3233
|
+
trustTrajectory: "stable",
|
|
3234
|
+
totalSessions: 0,
|
|
3235
|
+
preferredTimePeriod: "afternoon",
|
|
3236
|
+
energyDistribution: {},
|
|
3237
|
+
avgSessionMinutes: 0,
|
|
3238
|
+
baselineFrustration: 0,
|
|
3239
|
+
baselineExcitement: 0,
|
|
3240
|
+
sentimentTrend: "stable",
|
|
3241
|
+
frustrationCorrelations: { toolErrors: 0, longSessions: 0, lateNight: 0 },
|
|
3242
|
+
avgTurnsPerSession: 0,
|
|
3243
|
+
engagementTrend: "stable",
|
|
3244
|
+
nudgeStats: {}
|
|
3245
|
+
};
|
|
3246
|
+
}
|
|
3247
|
+
async function loadUserModel(filePath) {
|
|
3248
|
+
const fp = filePath ?? defaultModelPath();
|
|
3249
|
+
try {
|
|
3250
|
+
const raw = await fs13.readFile(fp, "utf-8");
|
|
3251
|
+
const parsed = JSON.parse(raw);
|
|
3252
|
+
if (parsed?.version !== 1) return null;
|
|
3253
|
+
return parsed;
|
|
3254
|
+
} catch {
|
|
3255
|
+
return null;
|
|
3256
|
+
}
|
|
3257
|
+
}
|
|
3258
|
+
async function saveUserModel(model, filePath) {
|
|
3259
|
+
const fp = filePath ?? defaultModelPath();
|
|
3260
|
+
const dir = path13.dirname(fp);
|
|
3261
|
+
await fs13.mkdir(dir, { recursive: true });
|
|
3262
|
+
const tmp = fp + `.tmp-${Date.now()}`;
|
|
3263
|
+
await fs13.writeFile(tmp, JSON.stringify(model, null, 2), "utf-8");
|
|
3264
|
+
await fs13.rename(tmp, fp);
|
|
3265
|
+
}
|
|
3266
|
+
function aggregateSession(model, snapshot) {
|
|
3267
|
+
const sessions = [...model.sessions, snapshot];
|
|
3268
|
+
while (sessions.length > MAX_SESSIONS) {
|
|
3269
|
+
sessions.shift();
|
|
3270
|
+
}
|
|
3271
|
+
const totalSessions = model.profile.totalSessions + 1;
|
|
3272
|
+
const profile = computeProfile(sessions, totalSessions);
|
|
3273
|
+
return {
|
|
3274
|
+
...model,
|
|
3275
|
+
sessions,
|
|
3276
|
+
profile,
|
|
3277
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3278
|
+
};
|
|
3279
|
+
}
|
|
3280
|
+
function computeProfile(sessions, totalSessions) {
|
|
3281
|
+
if (sessions.length === 0) return { ...emptyProfile(), totalSessions };
|
|
3282
|
+
const n = sessions.length;
|
|
3283
|
+
let trustScore = 0.5;
|
|
3284
|
+
for (const s of sessions) {
|
|
3285
|
+
trustScore = TRUST_ALPHA * ratingSignal(s) + (1 - TRUST_ALPHA) * trustScore;
|
|
3286
|
+
}
|
|
3287
|
+
const trustTrajectory = computeTrustTrajectory(sessions);
|
|
3288
|
+
const baselineFrustration = avg(sessions.map((s) => s.avgFrustration));
|
|
3289
|
+
const baselineExcitement = avg(sessions.map((s) => s.avgExcitement));
|
|
3290
|
+
const sentimentTrend = computeSentimentTrend(sessions);
|
|
3291
|
+
const energyDistribution = {};
|
|
3292
|
+
for (const s of sessions) {
|
|
3293
|
+
energyDistribution[s.timePeriod] = (energyDistribution[s.timePeriod] || 0) + 1;
|
|
3294
|
+
}
|
|
3295
|
+
const preferredTimePeriod = Object.entries(energyDistribution).sort(
|
|
3296
|
+
(a, b) => b[1] - a[1]
|
|
3297
|
+
)[0]?.[0] ?? "afternoon";
|
|
3298
|
+
const avgSessionMinutes = avg(sessions.map((s) => s.durationMinutes));
|
|
3299
|
+
const avgTurnsPerSession = avg(sessions.map((s) => s.turnCount));
|
|
3300
|
+
const engagementTrend = computeLinearTrend(sessions.map((s) => s.turnCount));
|
|
3301
|
+
const frustrationCorrelations = n >= MIN_SESSIONS_FOR_CORRELATIONS ? {
|
|
3302
|
+
toolErrors: pearsonR(
|
|
3303
|
+
sessions.map((s) => s.avgFrustration),
|
|
3304
|
+
sessions.map((s) => s.toolErrors)
|
|
3305
|
+
),
|
|
3306
|
+
longSessions: pearsonR(
|
|
3307
|
+
sessions.map((s) => s.avgFrustration),
|
|
3308
|
+
sessions.map((s) => s.durationMinutes)
|
|
3309
|
+
),
|
|
3310
|
+
lateNight: pearsonR(
|
|
3311
|
+
sessions.map((s) => s.avgFrustration),
|
|
3312
|
+
sessions.map((s) => s.timePeriod === "late-night" || s.timePeriod === "night" ? 1 : 0)
|
|
3313
|
+
)
|
|
3314
|
+
} : { toolErrors: 0, longSessions: 0, lateNight: 0 };
|
|
3315
|
+
const nudgeStats = {};
|
|
3316
|
+
for (const s of sessions) {
|
|
3317
|
+
const ratingVal = ratingToNumber(s.rating);
|
|
3318
|
+
for (const nudge of s.wellbeingNudges) {
|
|
3319
|
+
if (!nudgeStats[nudge]) nudgeStats[nudge] = { fired: 0, sessionRatingAfter: 0 };
|
|
3320
|
+
nudgeStats[nudge].fired++;
|
|
3321
|
+
nudgeStats[nudge].sessionRatingAfter += ratingVal;
|
|
3322
|
+
}
|
|
3323
|
+
}
|
|
3324
|
+
for (const key of Object.keys(nudgeStats)) {
|
|
3325
|
+
if (nudgeStats[key].fired > 0) {
|
|
3326
|
+
nudgeStats[key].sessionRatingAfter /= nudgeStats[key].fired;
|
|
3327
|
+
}
|
|
3328
|
+
}
|
|
3329
|
+
return {
|
|
3330
|
+
trustScore,
|
|
3331
|
+
trustTrajectory,
|
|
3332
|
+
totalSessions,
|
|
3333
|
+
preferredTimePeriod,
|
|
3334
|
+
energyDistribution,
|
|
3335
|
+
avgSessionMinutes,
|
|
3336
|
+
baselineFrustration,
|
|
3337
|
+
baselineExcitement,
|
|
3338
|
+
sentimentTrend,
|
|
3339
|
+
frustrationCorrelations,
|
|
3340
|
+
avgTurnsPerSession,
|
|
3341
|
+
engagementTrend,
|
|
3342
|
+
nudgeStats
|
|
3343
|
+
};
|
|
3344
|
+
}
|
|
3345
|
+
function feedForward(model) {
|
|
3346
|
+
if (model.profile.totalSessions < MIN_SESSIONS_FOR_FEED_FORWARD) return null;
|
|
3347
|
+
const p4 = model.profile;
|
|
3348
|
+
const overrides = {
|
|
3349
|
+
compactGreeting: false,
|
|
3350
|
+
frustrationNudgeThreshold: 0.6,
|
|
3351
|
+
defaultToPersonalMode: false
|
|
3352
|
+
};
|
|
3353
|
+
const nightSessions = (p4.energyDistribution["late-night"] || 0) + (p4.energyDistribution["night"] || 0);
|
|
3354
|
+
const totalInWindow = model.sessions.length;
|
|
3355
|
+
if (totalInWindow > 0 && nightSessions / totalInWindow >= 0.7 && p4.baselineFrustration < 0.3) {
|
|
3356
|
+
overrides.energyOverride = "steady";
|
|
3357
|
+
}
|
|
3358
|
+
if (p4.trustScore > 0.8) {
|
|
3359
|
+
overrides.compactGreeting = true;
|
|
3360
|
+
}
|
|
3361
|
+
if (p4.frustrationCorrelations.toolErrors > 0.4) {
|
|
3362
|
+
overrides.frustrationNudgeThreshold = 0.4;
|
|
3363
|
+
}
|
|
3364
|
+
if (p4.sentimentTrend === "worsening") {
|
|
3365
|
+
overrides.defaultToPersonalMode = true;
|
|
3366
|
+
}
|
|
3367
|
+
return overrides;
|
|
3368
|
+
}
|
|
3369
|
+
function clamp(val, min, max) {
|
|
3370
|
+
return Math.max(min, Math.min(max, val));
|
|
3371
|
+
}
|
|
3372
|
+
function avg(values) {
|
|
3373
|
+
if (values.length === 0) return 0;
|
|
3374
|
+
return values.reduce((sum, v) => sum + v, 0) / values.length;
|
|
3375
|
+
}
|
|
3376
|
+
function ratingSignal(session) {
|
|
3377
|
+
if (session.rating === "great") return 1;
|
|
3378
|
+
if (session.rating === "good") return 0.75;
|
|
3379
|
+
if (session.rating === "okay") return 0.5;
|
|
3380
|
+
if (session.rating === "frustrating") return 0.25;
|
|
3381
|
+
let implicit = 1;
|
|
3382
|
+
implicit -= session.avgFrustration * 0.4;
|
|
3383
|
+
implicit -= session.toolErrors > 3 ? 0.2 : 0;
|
|
3384
|
+
implicit -= session.blockers > 2 ? 0.2 : 0;
|
|
3385
|
+
implicit += session.milestones > 0 ? 0.1 : 0;
|
|
3386
|
+
return clamp(implicit, 0, 1);
|
|
3387
|
+
}
|
|
3388
|
+
function ratingToNumber(rating) {
|
|
3389
|
+
if (rating === "great") return 1;
|
|
3390
|
+
if (rating === "good") return 0.75;
|
|
3391
|
+
if (rating === "okay") return 0.5;
|
|
3392
|
+
if (rating === "frustrating") return 0.25;
|
|
3393
|
+
return 0.5;
|
|
3394
|
+
}
|
|
3395
|
+
function pearsonR(x, y) {
|
|
3396
|
+
const n = x.length;
|
|
3397
|
+
if (n < 3) return 0;
|
|
3398
|
+
const mx = avg(x);
|
|
3399
|
+
const my = avg(y);
|
|
3400
|
+
let num = 0;
|
|
3401
|
+
let dx2 = 0;
|
|
3402
|
+
let dy2 = 0;
|
|
3403
|
+
for (let i = 0; i < n; i++) {
|
|
3404
|
+
const dx = x[i] - mx;
|
|
3405
|
+
const dy = y[i] - my;
|
|
3406
|
+
num += dx * dy;
|
|
3407
|
+
dx2 += dx * dx;
|
|
3408
|
+
dy2 += dy * dy;
|
|
3409
|
+
}
|
|
3410
|
+
const denom = Math.sqrt(dx2 * dy2);
|
|
3411
|
+
if (denom === 0) return 0;
|
|
3412
|
+
return num / denom;
|
|
3413
|
+
}
|
|
3414
|
+
function computeTrustTrajectory(sessions) {
|
|
3415
|
+
if (sessions.length < 10) return "stable";
|
|
3416
|
+
const recent5 = sessions.slice(-5).map(ratingSignal);
|
|
3417
|
+
const prev5 = sessions.slice(-10, -5).map(ratingSignal);
|
|
3418
|
+
const recentAvg = avg(recent5);
|
|
3419
|
+
const prevAvg = avg(prev5);
|
|
3420
|
+
const delta = recentAvg - prevAvg;
|
|
3421
|
+
if (delta > 0.1) return "ascending";
|
|
3422
|
+
if (delta < -0.1) return "declining";
|
|
3423
|
+
return "stable";
|
|
3424
|
+
}
|
|
3425
|
+
function computeSentimentTrend(sessions) {
|
|
3426
|
+
if (sessions.length < 5) return "stable";
|
|
3427
|
+
const frustrations = sessions.slice(-10).map((s) => s.avgFrustration);
|
|
3428
|
+
const slope = linearSlope(frustrations);
|
|
3429
|
+
if (slope > 0.02) return "worsening";
|
|
3430
|
+
if (slope < -0.02) return "improving";
|
|
3431
|
+
return "stable";
|
|
3432
|
+
}
|
|
3433
|
+
function computeLinearTrend(values) {
|
|
3434
|
+
if (values.length < 5) return "stable";
|
|
3435
|
+
const recent = values.slice(-10);
|
|
3436
|
+
const slope = linearSlope(recent);
|
|
3437
|
+
const mean = avg(recent);
|
|
3438
|
+
const relativeSlope = mean > 0 ? slope / mean : slope;
|
|
3439
|
+
if (relativeSlope > 0.03) return "increasing";
|
|
3440
|
+
if (relativeSlope < -0.03) return "decreasing";
|
|
3441
|
+
return "stable";
|
|
3442
|
+
}
|
|
3443
|
+
function linearSlope(values) {
|
|
3444
|
+
const n = values.length;
|
|
3445
|
+
if (n < 2) return 0;
|
|
3446
|
+
let sumX = 0;
|
|
3447
|
+
let sumY = 0;
|
|
3448
|
+
let sumXY = 0;
|
|
3449
|
+
let sumX2 = 0;
|
|
3450
|
+
for (let i = 0; i < n; i++) {
|
|
3451
|
+
sumX += i;
|
|
3452
|
+
sumY += values[i];
|
|
3453
|
+
sumXY += i * values[i];
|
|
3454
|
+
sumX2 += i * i;
|
|
3455
|
+
}
|
|
3456
|
+
const denom = n * sumX2 - sumX * sumX;
|
|
3457
|
+
if (denom === 0) return 0;
|
|
3458
|
+
return (n * sumXY - sumX * sumY) / denom;
|
|
3459
|
+
}
|
|
3460
|
+
|
|
3203
3461
|
// src/hooks.ts
|
|
3204
3462
|
function getTimeContext() {
|
|
3205
3463
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -3347,6 +3605,29 @@ ${contextInjection}`;
|
|
|
3347
3605
|
sessionMinutes: 0,
|
|
3348
3606
|
turnCount: 0
|
|
3349
3607
|
});
|
|
3608
|
+
try {
|
|
3609
|
+
const model = await loadUserModel();
|
|
3610
|
+
if (model) {
|
|
3611
|
+
const overrides = feedForward(model);
|
|
3612
|
+
if (overrides) {
|
|
3613
|
+
log.debug("hooks", `Feed-forward active (trust=${model.profile.trustScore.toFixed(2)}, sessions=${model.profile.totalSessions})`);
|
|
3614
|
+
if (overrides.energyOverride && (period === "late-night" || period === "night")) {
|
|
3615
|
+
state.energy = overrides.energyOverride;
|
|
3616
|
+
}
|
|
3617
|
+
if (overrides.defaultToPersonalMode && state.activeMode === "Default") {
|
|
3618
|
+
state.activeMode = "Personal";
|
|
3619
|
+
}
|
|
3620
|
+
if (overrides.compactGreeting) {
|
|
3621
|
+
greeting += "\n<user-model-context>High trust user (score: " + model.profile.trustScore.toFixed(2) + ", " + model.profile.totalSessions + " sessions). Keep greeting compact \u2014 they know you well.</user-model-context>";
|
|
3622
|
+
}
|
|
3623
|
+
if (model.profile.sentimentTrend === "worsening") {
|
|
3624
|
+
greeting += "\n<user-model-context>Sentiment trend is worsening across recent sessions. Be more attentive and patient.</user-model-context>";
|
|
3625
|
+
}
|
|
3626
|
+
}
|
|
3627
|
+
}
|
|
3628
|
+
} catch (err) {
|
|
3629
|
+
log.debug("hooks", "user model feed-forward failed", err);
|
|
3630
|
+
}
|
|
3350
3631
|
syncPersonalityToCore(state, ctx.mcpManager).catch(() => {
|
|
3351
3632
|
});
|
|
3352
3633
|
const nudge = formatWellbeingNudge(state);
|
|
@@ -3468,10 +3749,10 @@ async function onSessionEnd(ctx, messages, sessionId, observationSession) {
|
|
|
3468
3749
|
}
|
|
3469
3750
|
console.log(pc2.dim(` Saved ${textMessages.length} messages (session: ${sessionId})`));
|
|
3470
3751
|
}
|
|
3471
|
-
const projectContextPath =
|
|
3472
|
-
if (
|
|
3752
|
+
const projectContextPath = path14.join(process.cwd(), ".acore", "context.md");
|
|
3753
|
+
if (fs14.existsSync(projectContextPath) && messages.length > 2) {
|
|
3473
3754
|
try {
|
|
3474
|
-
let contextContent =
|
|
3755
|
+
let contextContent = fs14.readFileSync(projectContextPath, "utf-8");
|
|
3475
3756
|
const now = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
3476
3757
|
let lastUserMsg = "";
|
|
3477
3758
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
@@ -3489,28 +3770,28 @@ async function onSessionEnd(ctx, messages, sessionId, observationSession) {
|
|
|
3489
3770
|
- Recent decisions: [see memory]
|
|
3490
3771
|
- Temp notes: [cleared]`;
|
|
3491
3772
|
contextContent = contextContent.replace(sessionPattern, newSession);
|
|
3492
|
-
|
|
3773
|
+
fs14.writeFileSync(projectContextPath, contextContent, "utf-8");
|
|
3493
3774
|
log.debug("hooks", `Updated project context: ${projectContextPath}`);
|
|
3494
3775
|
}
|
|
3495
3776
|
} catch (err) {
|
|
3496
3777
|
log.debug("hooks", "project context update failed", err);
|
|
3497
3778
|
}
|
|
3498
3779
|
}
|
|
3780
|
+
const sessionMinutes = Math.round((Date.now() - sessionStartTime) / 6e4);
|
|
3781
|
+
const hour = (/* @__PURE__ */ new Date()).getHours();
|
|
3782
|
+
let period;
|
|
3783
|
+
if (hour < 6) period = "late-night";
|
|
3784
|
+
else if (hour < 12) period = "morning";
|
|
3785
|
+
else if (hour < 17) period = "afternoon";
|
|
3786
|
+
else if (hour < 21) period = "evening";
|
|
3787
|
+
else period = "night";
|
|
3788
|
+
const turnCount = messages.filter((m) => m.role === "user").length;
|
|
3789
|
+
const finalState = computePersonality({
|
|
3790
|
+
timePeriod: period,
|
|
3791
|
+
sessionMinutes,
|
|
3792
|
+
turnCount
|
|
3793
|
+
});
|
|
3499
3794
|
if (ctx.config.personalityAdapt !== false) {
|
|
3500
|
-
const sessionMinutes = Math.round((Date.now() - sessionStartTime) / 6e4);
|
|
3501
|
-
const hour = (/* @__PURE__ */ new Date()).getHours();
|
|
3502
|
-
let period;
|
|
3503
|
-
if (hour < 6) period = "late-night";
|
|
3504
|
-
else if (hour < 12) period = "morning";
|
|
3505
|
-
else if (hour < 17) period = "afternoon";
|
|
3506
|
-
else if (hour < 21) period = "evening";
|
|
3507
|
-
else period = "night";
|
|
3508
|
-
const turnCount = messages.filter((m) => m.role === "user").length;
|
|
3509
|
-
const finalState = computePersonality({
|
|
3510
|
-
timePeriod: period,
|
|
3511
|
-
sessionMinutes,
|
|
3512
|
-
turnCount
|
|
3513
|
-
});
|
|
3514
3795
|
try {
|
|
3515
3796
|
isHookCall = true;
|
|
3516
3797
|
await syncPersonalityToCore(finalState, ctx.mcpManager);
|
|
@@ -3518,6 +3799,7 @@ async function onSessionEnd(ctx, messages, sessionId, observationSession) {
|
|
|
3518
3799
|
isHookCall = false;
|
|
3519
3800
|
}
|
|
3520
3801
|
}
|
|
3802
|
+
let sessionRating;
|
|
3521
3803
|
if (ctx.config.evalPrompt) {
|
|
3522
3804
|
const rating = await p2.select({
|
|
3523
3805
|
message: "Quick rating for this session?",
|
|
@@ -3530,10 +3812,11 @@ async function onSessionEnd(ctx, messages, sessionId, observationSession) {
|
|
|
3530
3812
|
initialValue: "skip"
|
|
3531
3813
|
});
|
|
3532
3814
|
if (!p2.isCancel(rating) && rating !== "skip") {
|
|
3815
|
+
sessionRating = rating;
|
|
3533
3816
|
try {
|
|
3534
3817
|
isHookCall = true;
|
|
3535
3818
|
await ctx.mcpManager.callTool("eval_log", {
|
|
3536
|
-
rating,
|
|
3819
|
+
rating: sessionRating,
|
|
3537
3820
|
highlights: "Quick session rating",
|
|
3538
3821
|
improvements: ""
|
|
3539
3822
|
});
|
|
@@ -3542,6 +3825,51 @@ async function onSessionEnd(ctx, messages, sessionId, observationSession) {
|
|
|
3542
3825
|
}
|
|
3543
3826
|
}
|
|
3544
3827
|
}
|
|
3828
|
+
if (turnCount >= 2 && sessionMinutes >= 1) {
|
|
3829
|
+
try {
|
|
3830
|
+
const snapshot = {
|
|
3831
|
+
sessionId,
|
|
3832
|
+
date: (/* @__PURE__ */ new Date()).toISOString().split("T")[0],
|
|
3833
|
+
durationMinutes: sessionMinutes,
|
|
3834
|
+
turnCount,
|
|
3835
|
+
dominantSentiment: finalState.sentiment.dominant,
|
|
3836
|
+
avgFrustration: finalState.sentiment.frustration,
|
|
3837
|
+
avgExcitement: finalState.sentiment.excitement,
|
|
3838
|
+
avgConfusion: finalState.sentiment.confusion,
|
|
3839
|
+
avgFatigue: finalState.sentiment.fatigue,
|
|
3840
|
+
toolCalls: observationSession?.stats.toolCalls ?? 0,
|
|
3841
|
+
toolErrors: observationSession?.stats.toolErrors ?? 0,
|
|
3842
|
+
blockers: observationSession?.stats.blockers ?? 0,
|
|
3843
|
+
milestones: observationSession?.stats.milestones ?? 0,
|
|
3844
|
+
topicShifts: observationSession?.stats.topicShifts ?? 0,
|
|
3845
|
+
peakEnergy: finalState.energy,
|
|
3846
|
+
primaryMode: finalState.activeMode,
|
|
3847
|
+
timePeriod: period,
|
|
3848
|
+
rating: sessionRating,
|
|
3849
|
+
hadPostmortem: false,
|
|
3850
|
+
// updated below if postmortem is generated
|
|
3851
|
+
wellbeingNudges: finalState.wellbeingNudge ? [finalState.wellbeingNudge] : []
|
|
3852
|
+
};
|
|
3853
|
+
const model = await loadUserModel() ?? createEmptyModel();
|
|
3854
|
+
const updated = aggregateSession(model, snapshot);
|
|
3855
|
+
await saveUserModel(updated);
|
|
3856
|
+
log.debug("hooks", `User model updated (session ${updated.profile.totalSessions})`);
|
|
3857
|
+
if (ctx.config.personalityAdapt !== false) {
|
|
3858
|
+
try {
|
|
3859
|
+
isHookCall = true;
|
|
3860
|
+
await syncPersonalityToCore(finalState, ctx.mcpManager, {
|
|
3861
|
+
trustScore: updated.profile.trustScore,
|
|
3862
|
+
totalSessions: updated.profile.totalSessions,
|
|
3863
|
+
sentimentTrend: updated.profile.sentimentTrend
|
|
3864
|
+
});
|
|
3865
|
+
} finally {
|
|
3866
|
+
isHookCall = false;
|
|
3867
|
+
}
|
|
3868
|
+
}
|
|
3869
|
+
} catch (err) {
|
|
3870
|
+
log.debug("hooks", "user model aggregation failed", err);
|
|
3871
|
+
}
|
|
3872
|
+
}
|
|
3545
3873
|
if (ctx.config.autoPostmortem !== false && observationSession && shouldAutoPostmortem(observationSession, messages)) {
|
|
3546
3874
|
try {
|
|
3547
3875
|
const client = ctx.llmClient;
|
|
@@ -3568,14 +3896,14 @@ async function onSessionEnd(ctx, messages, sessionId, observationSession) {
|
|
|
3568
3896
|
}
|
|
3569
3897
|
}
|
|
3570
3898
|
if (report.crystallizationCandidates && report.crystallizationCandidates.length > 0) {
|
|
3571
|
-
const skillsMdPath =
|
|
3572
|
-
const logPath =
|
|
3573
|
-
|
|
3899
|
+
const skillsMdPath = path14.join(os13.homedir(), ".askill", "skills.md");
|
|
3900
|
+
const logPath = path14.join(
|
|
3901
|
+
os13.homedir(),
|
|
3574
3902
|
".aman-agent",
|
|
3575
3903
|
"crystallization-log.json"
|
|
3576
3904
|
);
|
|
3577
|
-
const rejectionsPath =
|
|
3578
|
-
|
|
3905
|
+
const rejectionsPath = path14.join(
|
|
3906
|
+
os13.homedir(),
|
|
3579
3907
|
".aman-agent",
|
|
3580
3908
|
"crystallization-rejections.json"
|
|
3581
3909
|
);
|
|
@@ -3795,43 +4123,43 @@ async function delegatePipeline(steps, initialInput, client, mcpManager, options
|
|
|
3795
4123
|
}
|
|
3796
4124
|
|
|
3797
4125
|
// src/teams.ts
|
|
3798
|
-
import
|
|
3799
|
-
import
|
|
3800
|
-
import
|
|
4126
|
+
import fs15 from "fs";
|
|
4127
|
+
import path15 from "path";
|
|
4128
|
+
import os14 from "os";
|
|
3801
4129
|
import pc4 from "picocolors";
|
|
3802
4130
|
function getTeamsDir() {
|
|
3803
|
-
return
|
|
4131
|
+
return path15.join(os14.homedir(), ".acore", "teams");
|
|
3804
4132
|
}
|
|
3805
4133
|
function ensureTeamsDir() {
|
|
3806
4134
|
const dir = getTeamsDir();
|
|
3807
|
-
if (!
|
|
4135
|
+
if (!fs15.existsSync(dir)) fs15.mkdirSync(dir, { recursive: true });
|
|
3808
4136
|
return dir;
|
|
3809
4137
|
}
|
|
3810
4138
|
function teamPath(name) {
|
|
3811
4139
|
const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, "-");
|
|
3812
|
-
return
|
|
4140
|
+
return path15.join(ensureTeamsDir(), `${slug}.json`);
|
|
3813
4141
|
}
|
|
3814
4142
|
function createTeam(team) {
|
|
3815
4143
|
const fp = teamPath(team.name);
|
|
3816
|
-
|
|
4144
|
+
fs15.writeFileSync(fp, JSON.stringify(team, null, 2), "utf-8");
|
|
3817
4145
|
}
|
|
3818
4146
|
function loadTeam(name) {
|
|
3819
4147
|
const fp = teamPath(name);
|
|
3820
|
-
if (!
|
|
4148
|
+
if (!fs15.existsSync(fp)) return null;
|
|
3821
4149
|
try {
|
|
3822
|
-
return JSON.parse(
|
|
4150
|
+
return JSON.parse(fs15.readFileSync(fp, "utf-8"));
|
|
3823
4151
|
} catch {
|
|
3824
4152
|
return null;
|
|
3825
4153
|
}
|
|
3826
4154
|
}
|
|
3827
4155
|
function listTeams() {
|
|
3828
4156
|
const dir = getTeamsDir();
|
|
3829
|
-
if (!
|
|
4157
|
+
if (!fs15.existsSync(dir)) return [];
|
|
3830
4158
|
const teams = [];
|
|
3831
|
-
for (const file of
|
|
4159
|
+
for (const file of fs15.readdirSync(dir)) {
|
|
3832
4160
|
if (!file.endsWith(".json")) continue;
|
|
3833
4161
|
try {
|
|
3834
|
-
const content =
|
|
4162
|
+
const content = fs15.readFileSync(path15.join(dir, file), "utf-8");
|
|
3835
4163
|
teams.push(JSON.parse(content));
|
|
3836
4164
|
} catch {
|
|
3837
4165
|
}
|
|
@@ -3840,8 +4168,8 @@ function listTeams() {
|
|
|
3840
4168
|
}
|
|
3841
4169
|
function deleteTeam(name) {
|
|
3842
4170
|
const fp = teamPath(name);
|
|
3843
|
-
if (!
|
|
3844
|
-
|
|
4171
|
+
if (!fs15.existsSync(fp)) return false;
|
|
4172
|
+
fs15.unlinkSync(fp);
|
|
3845
4173
|
return true;
|
|
3846
4174
|
}
|
|
3847
4175
|
async function runTeam(team, task, client, mcpManager, tools) {
|
|
@@ -4067,23 +4395,23 @@ var BUILT_IN_TEAMS = [
|
|
|
4067
4395
|
];
|
|
4068
4396
|
|
|
4069
4397
|
// src/plans.ts
|
|
4070
|
-
import
|
|
4071
|
-
import
|
|
4072
|
-
import
|
|
4398
|
+
import fs16 from "fs";
|
|
4399
|
+
import path16 from "path";
|
|
4400
|
+
import os15 from "os";
|
|
4073
4401
|
function getPlansDir() {
|
|
4074
|
-
const localDir =
|
|
4075
|
-
const localAcore =
|
|
4076
|
-
if (
|
|
4077
|
-
return
|
|
4402
|
+
const localDir = path16.join(process.cwd(), ".acore", "plans");
|
|
4403
|
+
const localAcore = path16.join(process.cwd(), ".acore");
|
|
4404
|
+
if (fs16.existsSync(localAcore)) return localDir;
|
|
4405
|
+
return path16.join(os15.homedir(), ".acore", "plans");
|
|
4078
4406
|
}
|
|
4079
4407
|
function ensurePlansDir() {
|
|
4080
4408
|
const dir = getPlansDir();
|
|
4081
|
-
if (!
|
|
4409
|
+
if (!fs16.existsSync(dir)) fs16.mkdirSync(dir, { recursive: true });
|
|
4082
4410
|
return dir;
|
|
4083
4411
|
}
|
|
4084
4412
|
function planPath(name) {
|
|
4085
4413
|
const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
4086
|
-
return
|
|
4414
|
+
return path16.join(ensurePlansDir(), `${slug}.md`);
|
|
4087
4415
|
}
|
|
4088
4416
|
function serializePlan(plan) {
|
|
4089
4417
|
const lines = [];
|
|
@@ -4109,7 +4437,7 @@ function parsePlan(content, filePath) {
|
|
|
4109
4437
|
const createdMatch = content.match(/\*\*Created:\*\*\s*(.+)/);
|
|
4110
4438
|
const updatedMatch = content.match(/\*\*Updated:\*\*\s*(.+)/);
|
|
4111
4439
|
const activeMatch = content.match(/\*\*Active:\*\*\s*(.+)/);
|
|
4112
|
-
const name = nameMatch?.[1]?.trim() ||
|
|
4440
|
+
const name = nameMatch?.[1]?.trim() || path16.basename(filePath, ".md");
|
|
4113
4441
|
const goal = goalMatch?.[1]?.trim() || "";
|
|
4114
4442
|
const createdAt = createdMatch?.[1]?.trim() || "";
|
|
4115
4443
|
const updatedAt = updatedMatch?.[1]?.trim() || "";
|
|
@@ -4151,22 +4479,22 @@ function createPlan(name, goal, steps) {
|
|
|
4151
4479
|
}
|
|
4152
4480
|
function savePlan(plan) {
|
|
4153
4481
|
const fp = planPath(plan.name);
|
|
4154
|
-
|
|
4482
|
+
fs16.writeFileSync(fp, serializePlan(plan), "utf-8");
|
|
4155
4483
|
}
|
|
4156
4484
|
function loadPlan(name) {
|
|
4157
4485
|
const fp = planPath(name);
|
|
4158
|
-
if (!
|
|
4159
|
-
const content =
|
|
4486
|
+
if (!fs16.existsSync(fp)) return null;
|
|
4487
|
+
const content = fs16.readFileSync(fp, "utf-8");
|
|
4160
4488
|
return parsePlan(content, fp);
|
|
4161
4489
|
}
|
|
4162
4490
|
function listPlans() {
|
|
4163
4491
|
const dir = getPlansDir();
|
|
4164
|
-
if (!
|
|
4492
|
+
if (!fs16.existsSync(dir)) return [];
|
|
4165
4493
|
const plans = [];
|
|
4166
|
-
for (const file of
|
|
4494
|
+
for (const file of fs16.readdirSync(dir)) {
|
|
4167
4495
|
if (!file.endsWith(".md")) continue;
|
|
4168
|
-
const fp =
|
|
4169
|
-
const content =
|
|
4496
|
+
const fp = path16.join(dir, file);
|
|
4497
|
+
const content = fs16.readFileSync(fp, "utf-8");
|
|
4170
4498
|
const plan = parsePlan(content, fp);
|
|
4171
4499
|
if (plan) plans.push(plan);
|
|
4172
4500
|
}
|
|
@@ -4275,10 +4603,10 @@ import {
|
|
|
4275
4603
|
} from "@aman_asmuei/arules-core";
|
|
4276
4604
|
var AGENT_SCOPE = process.env.AMAN_AGENT_SCOPE ?? "dev:agent";
|
|
4277
4605
|
function readEcosystemFile(filePath, label) {
|
|
4278
|
-
if (!
|
|
4606
|
+
if (!fs17.existsSync(filePath)) {
|
|
4279
4607
|
return pc5.dim(`No ${label} file found at ${filePath}`);
|
|
4280
4608
|
}
|
|
4281
|
-
return
|
|
4609
|
+
return fs17.readFileSync(filePath, "utf-8").trim();
|
|
4282
4610
|
}
|
|
4283
4611
|
function parseCommand(input) {
|
|
4284
4612
|
const trimmed = input.trim();
|
|
@@ -4356,24 +4684,76 @@ async function handleIdentityCommand(action, args, _ctx) {
|
|
|
4356
4684
|
}
|
|
4357
4685
|
}
|
|
4358
4686
|
if (action === "dynamics") {
|
|
4687
|
+
if (args.includes("--json")) {
|
|
4688
|
+
const model2 = await loadUserModel();
|
|
4689
|
+
if (!model2) return { handled: true, output: pc5.dim("No user model yet. Complete a few sessions first.") };
|
|
4690
|
+
return { handled: true, output: JSON.stringify(model2, null, 2) };
|
|
4691
|
+
}
|
|
4692
|
+
if (args.includes("--reset")) {
|
|
4693
|
+
const modelPath = defaultModelPath();
|
|
4694
|
+
if (fs17.existsSync(modelPath)) {
|
|
4695
|
+
fs17.unlinkSync(modelPath);
|
|
4696
|
+
return { handled: true, output: pc5.green("User model reset. Starting fresh.") };
|
|
4697
|
+
}
|
|
4698
|
+
return { handled: true, output: pc5.dim("No user model to reset.") };
|
|
4699
|
+
}
|
|
4359
4700
|
const updates = {};
|
|
4360
4701
|
for (const arg of args) {
|
|
4361
4702
|
const eq = arg.indexOf("=");
|
|
4362
4703
|
if (eq > 0) updates[arg.slice(0, eq)] = arg.slice(eq + 1);
|
|
4363
4704
|
}
|
|
4364
|
-
if (
|
|
4365
|
-
|
|
4705
|
+
if (Object.keys(updates).length > 0) {
|
|
4706
|
+
try {
|
|
4707
|
+
await acoreUpdateDynamics({
|
|
4708
|
+
energy: updates.energy,
|
|
4709
|
+
activeMode: updates.mode,
|
|
4710
|
+
currentRead: updates.read
|
|
4711
|
+
}, AGENT_SCOPE);
|
|
4712
|
+
return { handled: true, output: `Dynamics updated: ${Object.entries(updates).map(([k, v]) => `${k}=${v}`).join(", ")}` };
|
|
4713
|
+
} catch (err) {
|
|
4714
|
+
return { handled: true, output: pc5.red(`Dynamics error: ${err instanceof Error ? err.message : String(err)}`) };
|
|
4715
|
+
}
|
|
4366
4716
|
}
|
|
4367
|
-
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
|
|
4717
|
+
const model = await loadUserModel();
|
|
4718
|
+
if (!model) {
|
|
4719
|
+
return { handled: true, output: pc5.dim("No user model yet. Complete a few sessions to start building your profile.") };
|
|
4720
|
+
}
|
|
4721
|
+
const p4 = model.profile;
|
|
4722
|
+
const trustBar = "\u2588".repeat(Math.round(p4.trustScore * 10)) + "\u2591".repeat(10 - Math.round(p4.trustScore * 10));
|
|
4723
|
+
const frustBar = "\u2588".repeat(Math.round(p4.baselineFrustration * 10)) + "\u2591".repeat(10 - Math.round(p4.baselineFrustration * 10));
|
|
4724
|
+
const lines = [
|
|
4725
|
+
pc5.bold(" Dynamic User Model"),
|
|
4726
|
+
"",
|
|
4727
|
+
` ${pc5.cyan("Trust")} ${trustBar} ${(p4.trustScore * 100).toFixed(0)}% ${p4.trustTrajectory === "ascending" ? pc5.green("\u2191") : p4.trustTrajectory === "declining" ? pc5.red("\u2193") : "\u2192"}`,
|
|
4728
|
+
` ${pc5.cyan("Sessions")} ${p4.totalSessions} total (${model.sessions.length} in window)`,
|
|
4729
|
+
` ${pc5.cyan("Sentiment")} ${frustBar} frustration baseline ${p4.sentimentTrend === "improving" ? pc5.green("improving") : p4.sentimentTrend === "worsening" ? pc5.red("worsening") : "stable"}`,
|
|
4730
|
+
"",
|
|
4731
|
+
` ${pc5.cyan("Preferred")} ${p4.preferredTimePeriod} (${Object.entries(p4.energyDistribution).map(([k, v]) => `${k}: ${v}`).join(", ")})`,
|
|
4732
|
+
` ${pc5.cyan("Avg session")} ${p4.avgSessionMinutes.toFixed(0)} min, ${p4.avgTurnsPerSession.toFixed(0)} turns ${p4.engagementTrend === "increasing" ? pc5.green("\u2191") : p4.engagementTrend === "decreasing" ? pc5.red("\u2193") : "\u2192"}`
|
|
4733
|
+
];
|
|
4734
|
+
if (p4.totalSessions >= 10) {
|
|
4735
|
+
const corrs = [];
|
|
4736
|
+
if (Math.abs(p4.frustrationCorrelations.toolErrors) > 0.3) {
|
|
4737
|
+
corrs.push(`tool errors (${p4.frustrationCorrelations.toolErrors.toFixed(2)})`);
|
|
4738
|
+
}
|
|
4739
|
+
if (Math.abs(p4.frustrationCorrelations.longSessions) > 0.3) {
|
|
4740
|
+
corrs.push(`long sessions (${p4.frustrationCorrelations.longSessions.toFixed(2)})`);
|
|
4741
|
+
}
|
|
4742
|
+
if (Math.abs(p4.frustrationCorrelations.lateNight) > 0.3) {
|
|
4743
|
+
corrs.push(`late night (${p4.frustrationCorrelations.lateNight.toFixed(2)})`);
|
|
4744
|
+
}
|
|
4745
|
+
if (corrs.length > 0) {
|
|
4746
|
+
lines.push(` ${pc5.cyan("Frustration")} correlates with: ${corrs.join(", ")}`);
|
|
4747
|
+
}
|
|
4748
|
+
}
|
|
4749
|
+
const nudgeKeys = Object.keys(p4.nudgeStats);
|
|
4750
|
+
if (nudgeKeys.length > 0) {
|
|
4751
|
+
lines.push("");
|
|
4752
|
+
lines.push(` ${pc5.cyan("Nudges")} ${nudgeKeys.map((k) => `${k}: ${p4.nudgeStats[k].fired}\xD7`).join(", ")}`);
|
|
4376
4753
|
}
|
|
4754
|
+
lines.push("");
|
|
4755
|
+
lines.push(pc5.dim(` Use --json for raw data, --reset to start fresh`));
|
|
4756
|
+
return { handled: true, output: lines.join("\n") };
|
|
4377
4757
|
}
|
|
4378
4758
|
if (action === "summary") {
|
|
4379
4759
|
try {
|
|
@@ -4397,7 +4777,10 @@ async function handleIdentityCommand(action, args, _ctx) {
|
|
|
4397
4777
|
pc5.bold("Identity commands:"),
|
|
4398
4778
|
` ${pc5.cyan("/identity")} View current identity`,
|
|
4399
4779
|
` ${pc5.cyan("/identity update")} <section> Update a section`,
|
|
4780
|
+
` ${pc5.cyan("/identity dynamics")} View user model (trust, sentiment, patterns)`,
|
|
4400
4781
|
` ${pc5.cyan("/identity dynamics")} key=val Update dynamic fields (energy, mode, read)`,
|
|
4782
|
+
` ${pc5.cyan("/identity dynamics")} --json Raw JSON user model`,
|
|
4783
|
+
` ${pc5.cyan("/identity dynamics")} --reset Reset user model`,
|
|
4401
4784
|
` ${pc5.cyan("/identity summary")} Show structured identity summary`
|
|
4402
4785
|
].join("\n")
|
|
4403
4786
|
};
|
|
@@ -4553,9 +4936,9 @@ ${result.violations.map((v) => ` - ${v}`).join("\n")}`)
|
|
|
4553
4936
|
};
|
|
4554
4937
|
}
|
|
4555
4938
|
async function handleWorkflowsCommand(action, args, ctx) {
|
|
4556
|
-
const home2 =
|
|
4939
|
+
const home2 = os16.homedir();
|
|
4557
4940
|
if (!action) {
|
|
4558
|
-
const content = readEcosystemFile(
|
|
4941
|
+
const content = readEcosystemFile(path17.join(home2, ".aflow", "flow.md"), "workflows (aflow)");
|
|
4559
4942
|
return { handled: true, output: content };
|
|
4560
4943
|
}
|
|
4561
4944
|
if (action === "add") {
|
|
@@ -4577,7 +4960,7 @@ async function handleWorkflowsCommand(action, args, ctx) {
|
|
|
4577
4960
|
return { handled: true, output: pc5.yellow("Usage: /workflows get <name>") };
|
|
4578
4961
|
}
|
|
4579
4962
|
const name = args.join(" ").toLowerCase();
|
|
4580
|
-
const raw = readEcosystemFile(
|
|
4963
|
+
const raw = readEcosystemFile(path17.join(home2, ".aflow", "flow.md"), "workflows (aflow)");
|
|
4581
4964
|
if (raw.startsWith("No ")) {
|
|
4582
4965
|
return { handled: true, output: raw };
|
|
4583
4966
|
}
|
|
@@ -4636,12 +5019,12 @@ async function handleToolsCommand(action, args, _ctx) {
|
|
|
4636
5019
|
return { handled: true, output: pc5.yellow("Usage: /tools search <query...>") };
|
|
4637
5020
|
}
|
|
4638
5021
|
const query = args.join(" ").toLowerCase();
|
|
4639
|
-
const home2 =
|
|
4640
|
-
const toolsFile =
|
|
4641
|
-
if (!
|
|
5022
|
+
const home2 = os16.homedir();
|
|
5023
|
+
const toolsFile = path17.join(home2, ".akit", "tools.md");
|
|
5024
|
+
if (!fs17.existsSync(toolsFile)) {
|
|
4642
5025
|
return { handled: true, output: pc5.dim(`No tools file found. Use 'npx @aman_asmuei/akit search ${args.join(" ")}' to search the registry.`) };
|
|
4643
5026
|
}
|
|
4644
|
-
const raw =
|
|
5027
|
+
const raw = fs17.readFileSync(toolsFile, "utf-8").trim();
|
|
4645
5028
|
const lines = raw.split("\n");
|
|
4646
5029
|
const matches = lines.filter((l) => l.toLowerCase().includes(query));
|
|
4647
5030
|
if (matches.length === 0) {
|
|
@@ -4652,9 +5035,9 @@ async function handleToolsCommand(action, args, _ctx) {
|
|
|
4652
5035
|
return handleAkitCommand(action, args);
|
|
4653
5036
|
}
|
|
4654
5037
|
async function handleSkillsCommand(action, args, ctx) {
|
|
4655
|
-
const home2 =
|
|
5038
|
+
const home2 = os16.homedir();
|
|
4656
5039
|
if (!action) {
|
|
4657
|
-
const content = readEcosystemFile(
|
|
5040
|
+
const content = readEcosystemFile(path17.join(home2, ".askill", "skills.md"), "skills (askill)");
|
|
4658
5041
|
return { handled: true, output: content };
|
|
4659
5042
|
}
|
|
4660
5043
|
if (action === "install") {
|
|
@@ -4676,8 +5059,8 @@ async function handleSkillsCommand(action, args, ctx) {
|
|
|
4676
5059
|
return { handled: true, output: pc5.yellow("Usage: /skills search <query...>") };
|
|
4677
5060
|
}
|
|
4678
5061
|
const query = args.join(" ").toLowerCase();
|
|
4679
|
-
const home3 =
|
|
4680
|
-
const raw = readEcosystemFile(
|
|
5062
|
+
const home3 = os16.homedir();
|
|
5063
|
+
const raw = readEcosystemFile(path17.join(home3, ".askill", "skills.md"), "skills (askill)");
|
|
4681
5064
|
if (raw.startsWith("No ")) {
|
|
4682
5065
|
return { handled: true, output: raw };
|
|
4683
5066
|
}
|
|
@@ -4691,9 +5074,9 @@ async function handleSkillsCommand(action, args, ctx) {
|
|
|
4691
5074
|
if (action === "list") {
|
|
4692
5075
|
const autoOnly = args.includes("--auto");
|
|
4693
5076
|
if (autoOnly) {
|
|
4694
|
-
const logPath =
|
|
5077
|
+
const logPath = path17.join(os16.homedir(), ".aman-agent", "crystallization-log.json");
|
|
4695
5078
|
try {
|
|
4696
|
-
const content2 =
|
|
5079
|
+
const content2 = fs17.readFileSync(logPath, "utf-8");
|
|
4697
5080
|
const entries = JSON.parse(content2);
|
|
4698
5081
|
if (entries.length === 0) {
|
|
4699
5082
|
return { handled: true, output: pc5.dim("No crystallized skills yet.") };
|
|
@@ -4709,13 +5092,13 @@ async function handleSkillsCommand(action, args, ctx) {
|
|
|
4709
5092
|
return { handled: true, output: pc5.dim("No crystallized skills yet.") };
|
|
4710
5093
|
}
|
|
4711
5094
|
}
|
|
4712
|
-
const content = readEcosystemFile(
|
|
5095
|
+
const content = readEcosystemFile(path17.join(home2, ".askill", "skills.md"), "skills (askill)");
|
|
4713
5096
|
return { handled: true, output: content };
|
|
4714
5097
|
}
|
|
4715
5098
|
if (action === "crystallize") {
|
|
4716
|
-
const pmDir =
|
|
5099
|
+
const pmDir = path17.join(os16.homedir(), ".acore", "postmortems");
|
|
4717
5100
|
try {
|
|
4718
|
-
const files =
|
|
5101
|
+
const files = fs17.readdirSync(pmDir);
|
|
4719
5102
|
const jsonFiles = files.filter((f) => f.endsWith(".json")).sort().reverse();
|
|
4720
5103
|
if (jsonFiles.length === 0) {
|
|
4721
5104
|
return {
|
|
@@ -4724,7 +5107,7 @@ async function handleSkillsCommand(action, args, ctx) {
|
|
|
4724
5107
|
};
|
|
4725
5108
|
}
|
|
4726
5109
|
const latest = jsonFiles[0];
|
|
4727
|
-
const content =
|
|
5110
|
+
const content = fs17.readFileSync(path17.join(pmDir, latest), "utf-8");
|
|
4728
5111
|
const report = JSON.parse(content);
|
|
4729
5112
|
if (!report.crystallizationCandidates || report.crystallizationCandidates.length === 0) {
|
|
4730
5113
|
return {
|
|
@@ -4732,8 +5115,8 @@ async function handleSkillsCommand(action, args, ctx) {
|
|
|
4732
5115
|
output: pc5.dim(`No crystallization candidates in the most recent post-mortem (${latest}). Run a longer session or wait for the next auto-postmortem.`)
|
|
4733
5116
|
};
|
|
4734
5117
|
}
|
|
4735
|
-
const skillsMdPath =
|
|
4736
|
-
const logPath =
|
|
5118
|
+
const skillsMdPath = path17.join(os16.homedir(), ".askill", "skills.md");
|
|
5119
|
+
const logPath = path17.join(os16.homedir(), ".aman-agent", "crystallization-log.json");
|
|
4737
5120
|
const postmortemFilename = latest.replace(/\.json$/, ".md");
|
|
4738
5121
|
const lines = [
|
|
4739
5122
|
pc5.bold(`Found ${report.crystallizationCandidates.length} candidate(s) in ${latest}:`)
|
|
@@ -4790,9 +5173,9 @@ async function handleSkillsCommand(action, args, ctx) {
|
|
|
4790
5173
|
return { handled: true, output: pc5.yellow(`Unknown action: /skills ${action}. Try /skills --help`) };
|
|
4791
5174
|
}
|
|
4792
5175
|
async function handleEvalCommand(action, args, ctx) {
|
|
4793
|
-
const home2 =
|
|
5176
|
+
const home2 = os16.homedir();
|
|
4794
5177
|
if (!action) {
|
|
4795
|
-
const content = readEcosystemFile(
|
|
5178
|
+
const content = readEcosystemFile(path17.join(home2, ".aeval", "eval.md"), "evaluation (aeval)");
|
|
4796
5179
|
return { handled: true, output: content };
|
|
4797
5180
|
}
|
|
4798
5181
|
if (action === "milestone") {
|
|
@@ -4804,11 +5187,11 @@ async function handleEvalCommand(action, args, ctx) {
|
|
|
4804
5187
|
return { handled: true, output };
|
|
4805
5188
|
}
|
|
4806
5189
|
if (action === "report") {
|
|
4807
|
-
const evalFile =
|
|
4808
|
-
if (!
|
|
5190
|
+
const evalFile = path17.join(home2, ".aeval", "eval.md");
|
|
5191
|
+
if (!fs17.existsSync(evalFile)) {
|
|
4809
5192
|
return { handled: true, output: pc5.dim("No eval report found. Log milestones with /eval milestone <text>.") };
|
|
4810
5193
|
}
|
|
4811
|
-
const content =
|
|
5194
|
+
const content = fs17.readFileSync(evalFile, "utf-8").trim();
|
|
4812
5195
|
return { handled: true, output: [pc5.bold("Eval Report"), "", content].join("\n") };
|
|
4813
5196
|
}
|
|
4814
5197
|
return { handled: true, output: pc5.yellow(`Unknown action: /eval ${action}. Use /eval, /eval report, or /eval milestone <text>.`) };
|
|
@@ -5332,10 +5715,10 @@ function handleSave() {
|
|
|
5332
5715
|
}
|
|
5333
5716
|
function handleReset(action) {
|
|
5334
5717
|
const dirs = {
|
|
5335
|
-
config:
|
|
5336
|
-
memory:
|
|
5337
|
-
identity:
|
|
5338
|
-
rules:
|
|
5718
|
+
config: path17.join(os16.homedir(), ".aman-agent"),
|
|
5719
|
+
memory: path17.join(os16.homedir(), ".amem"),
|
|
5720
|
+
identity: path17.join(os16.homedir(), ".acore"),
|
|
5721
|
+
rules: path17.join(os16.homedir(), ".arules")
|
|
5339
5722
|
};
|
|
5340
5723
|
if (action === "help" || !action) {
|
|
5341
5724
|
return {
|
|
@@ -5360,15 +5743,15 @@ function handleReset(action) {
|
|
|
5360
5743
|
const removed = [];
|
|
5361
5744
|
for (const target of targets) {
|
|
5362
5745
|
const dir = dirs[target];
|
|
5363
|
-
if (
|
|
5364
|
-
|
|
5746
|
+
if (fs17.existsSync(dir)) {
|
|
5747
|
+
fs17.rmSync(dir, { recursive: true, force: true });
|
|
5365
5748
|
removed.push(target);
|
|
5366
5749
|
}
|
|
5367
5750
|
}
|
|
5368
5751
|
if (targets.includes("config")) {
|
|
5369
5752
|
const configDir = dirs.config;
|
|
5370
|
-
|
|
5371
|
-
|
|
5753
|
+
fs17.mkdirSync(configDir, { recursive: true });
|
|
5754
|
+
fs17.writeFileSync(path17.join(configDir, ".reconfig"), "", "utf-8");
|
|
5372
5755
|
}
|
|
5373
5756
|
if (removed.length === 0) {
|
|
5374
5757
|
return { handled: true, output: pc5.dim("Nothing to reset \u2014 directories don't exist.") };
|
|
@@ -5385,7 +5768,7 @@ function handleReset(action) {
|
|
|
5385
5768
|
function handleUpdate() {
|
|
5386
5769
|
try {
|
|
5387
5770
|
const current = execFileSync3("npm", ["view", "@aman_asmuei/aman-agent", "version"], { encoding: "utf-8" }).trim();
|
|
5388
|
-
const local = true ? "0.
|
|
5771
|
+
const local = true ? "0.27.0" : "unknown";
|
|
5389
5772
|
if (current === local) {
|
|
5390
5773
|
return { handled: true, output: `${pc5.green("Up to date")} \u2014 v${local}` };
|
|
5391
5774
|
}
|
|
@@ -5429,11 +5812,11 @@ function handleExportCommand() {
|
|
|
5429
5812
|
return { handled: true, exportConversation: true };
|
|
5430
5813
|
}
|
|
5431
5814
|
function handleDebugCommand() {
|
|
5432
|
-
const logPath =
|
|
5433
|
-
if (!
|
|
5815
|
+
const logPath = path17.join(os16.homedir(), ".aman-agent", "debug.log");
|
|
5816
|
+
if (!fs17.existsSync(logPath)) {
|
|
5434
5817
|
return { handled: true, output: pc5.dim("No debug log found.") };
|
|
5435
5818
|
}
|
|
5436
|
-
const content =
|
|
5819
|
+
const content = fs17.readFileSync(logPath, "utf-8");
|
|
5437
5820
|
const lines = content.trim().split("\n");
|
|
5438
5821
|
const last20 = lines.slice(-20).join("\n");
|
|
5439
5822
|
return { handled: true, output: pc5.bold("Debug Log (last 20 entries):\n") + pc5.dim(last20) };
|
|
@@ -5631,7 +6014,7 @@ ${result.response}`
|
|
|
5631
6014
|
};
|
|
5632
6015
|
}
|
|
5633
6016
|
function handleProfileCommand(action, args) {
|
|
5634
|
-
const profilesDir =
|
|
6017
|
+
const profilesDir = path17.join(os16.homedir(), ".acore", "profiles");
|
|
5635
6018
|
if (action === "me") {
|
|
5636
6019
|
const user = loadUserIdentity();
|
|
5637
6020
|
if (!user) {
|
|
@@ -5699,8 +6082,8 @@ ${pc5.dim("Edit with: /profile edit")}` };
|
|
|
5699
6082
|
};
|
|
5700
6083
|
}
|
|
5701
6084
|
const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, "-");
|
|
5702
|
-
const profileDir =
|
|
5703
|
-
if (
|
|
6085
|
+
const profileDir = path17.join(profilesDir, slug);
|
|
6086
|
+
if (fs17.existsSync(profileDir)) {
|
|
5704
6087
|
return { handled: true, output: pc5.yellow(`Profile already exists: ${slug}`) };
|
|
5705
6088
|
}
|
|
5706
6089
|
const builtIn = BUILT_IN_PROFILES.find((t) => t.name === slug);
|
|
@@ -5716,16 +6099,16 @@ ${pc5.dim("Edit with: /profile edit")}` };
|
|
|
5716
6099
|
Use: aman-agent --profile ${slug}`
|
|
5717
6100
|
};
|
|
5718
6101
|
}
|
|
5719
|
-
|
|
5720
|
-
const globalCore =
|
|
5721
|
-
if (
|
|
5722
|
-
let content =
|
|
6102
|
+
fs17.mkdirSync(profileDir, { recursive: true });
|
|
6103
|
+
const globalCore = path17.join(os16.homedir(), ".acore", "core.md");
|
|
6104
|
+
if (fs17.existsSync(globalCore)) {
|
|
6105
|
+
let content = fs17.readFileSync(globalCore, "utf-8");
|
|
5723
6106
|
const aiName = name.charAt(0).toUpperCase() + name.slice(1);
|
|
5724
6107
|
content = content.replace(/^# .+$/m, `# ${aiName}`);
|
|
5725
|
-
|
|
6108
|
+
fs17.writeFileSync(path17.join(profileDir, "core.md"), content, "utf-8");
|
|
5726
6109
|
} else {
|
|
5727
6110
|
const aiName = name.charAt(0).toUpperCase() + name.slice(1);
|
|
5728
|
-
|
|
6111
|
+
fs17.writeFileSync(path17.join(profileDir, "core.md"), `# ${aiName}
|
|
5729
6112
|
|
|
5730
6113
|
## Identity
|
|
5731
6114
|
- Role: ${aiName} is your AI companion
|
|
@@ -5738,7 +6121,7 @@ ${pc5.dim("Edit with: /profile edit")}` };
|
|
|
5738
6121
|
return {
|
|
5739
6122
|
handled: true,
|
|
5740
6123
|
output: pc5.green(`Profile created: ${slug}`) + `
|
|
5741
|
-
Edit: ${
|
|
6124
|
+
Edit: ${path17.join(profileDir, "core.md")}
|
|
5742
6125
|
Use: aman-agent --profile ${slug}
|
|
5743
6126
|
|
|
5744
6127
|
${pc5.dim("Add rules.md or skills.md for profile-specific overrides.")}`
|
|
@@ -5747,9 +6130,9 @@ ${pc5.dim("Edit with: /profile edit")}` };
|
|
|
5747
6130
|
case "show": {
|
|
5748
6131
|
const name = args[0];
|
|
5749
6132
|
if (!name) return { handled: true, output: pc5.yellow("Usage: /profile show <name>") };
|
|
5750
|
-
const profileDir =
|
|
5751
|
-
if (!
|
|
5752
|
-
const files =
|
|
6133
|
+
const profileDir = path17.join(profilesDir, name);
|
|
6134
|
+
if (!fs17.existsSync(profileDir)) return { handled: true, output: pc5.red(`Profile not found: ${name}`) };
|
|
6135
|
+
const files = fs17.readdirSync(profileDir).filter((f) => f.endsWith(".md"));
|
|
5753
6136
|
const lines = files.map((f) => ` ${f}`);
|
|
5754
6137
|
return { handled: true, output: `Profile: ${pc5.bold(name)}
|
|
5755
6138
|
Files:
|
|
@@ -5758,9 +6141,9 @@ ${lines.join("\n")}` };
|
|
|
5758
6141
|
case "delete": {
|
|
5759
6142
|
const name = args[0];
|
|
5760
6143
|
if (!name) return { handled: true, output: pc5.yellow("Usage: /profile delete <name>") };
|
|
5761
|
-
const profileDir =
|
|
5762
|
-
if (!
|
|
5763
|
-
|
|
6144
|
+
const profileDir = path17.join(profilesDir, name);
|
|
6145
|
+
if (!fs17.existsSync(profileDir)) return { handled: true, output: pc5.red(`Profile not found: ${name}`) };
|
|
6146
|
+
fs17.rmSync(profileDir, { recursive: true });
|
|
5764
6147
|
return { handled: true, output: pc5.dim(`Profile deleted: ${name}`) };
|
|
5765
6148
|
}
|
|
5766
6149
|
case "help":
|
|
@@ -5978,10 +6361,10 @@ function handleShowcaseCommand(action, args) {
|
|
|
5978
6361
|
Or place it as a sibling directory to aman-agent.`
|
|
5979
6362
|
};
|
|
5980
6363
|
}
|
|
5981
|
-
const corePath =
|
|
6364
|
+
const corePath = path17.join(os16.homedir(), ".acore", "core.md");
|
|
5982
6365
|
let currentShowcase = null;
|
|
5983
|
-
if (
|
|
5984
|
-
const content =
|
|
6366
|
+
if (fs17.existsSync(corePath)) {
|
|
6367
|
+
const content = fs17.readFileSync(corePath, "utf-8");
|
|
5985
6368
|
const nameMatch = content.match(/^# (.+)/m);
|
|
5986
6369
|
if (nameMatch) {
|
|
5987
6370
|
const coreName = nameMatch[1].trim().toLowerCase();
|
|
@@ -6368,10 +6751,10 @@ ${summaryParts.slice(0, 20).join("\n")}
|
|
|
6368
6751
|
}
|
|
6369
6752
|
|
|
6370
6753
|
// src/skill-engine.ts
|
|
6371
|
-
import
|
|
6754
|
+
import fs18 from "fs";
|
|
6372
6755
|
import fsp from "fs/promises";
|
|
6373
|
-
import
|
|
6374
|
-
import
|
|
6756
|
+
import path18 from "path";
|
|
6757
|
+
import os17 from "os";
|
|
6375
6758
|
var SKILL_TRIGGERS = {
|
|
6376
6759
|
testing: ["test", "spec", "coverage", "tdd", "jest", "vitest", "mocha", "assert", "mock", "stub", "fixture", "e2e", "integration test", "unit test"],
|
|
6377
6760
|
"api-design": ["api", "endpoint", "rest", "graphql", "route", "controller", "middleware", "http", "request", "response", "status code", "pagination"],
|
|
@@ -6400,20 +6783,20 @@ async function loadRuntimeTriggers(skillsMdPath) {
|
|
|
6400
6783
|
return /* @__PURE__ */ new Map();
|
|
6401
6784
|
}
|
|
6402
6785
|
}
|
|
6403
|
-
var LEVEL_FILE =
|
|
6786
|
+
var LEVEL_FILE = path18.join(os17.homedir(), ".aman-agent", "skill-levels.json");
|
|
6404
6787
|
function loadSkillLevels() {
|
|
6405
6788
|
try {
|
|
6406
|
-
if (
|
|
6407
|
-
return JSON.parse(
|
|
6789
|
+
if (fs18.existsSync(LEVEL_FILE)) {
|
|
6790
|
+
return JSON.parse(fs18.readFileSync(LEVEL_FILE, "utf-8"));
|
|
6408
6791
|
}
|
|
6409
6792
|
} catch {
|
|
6410
6793
|
}
|
|
6411
6794
|
return {};
|
|
6412
6795
|
}
|
|
6413
6796
|
function saveSkillLevels(levels) {
|
|
6414
|
-
const dir =
|
|
6415
|
-
if (!
|
|
6416
|
-
|
|
6797
|
+
const dir = path18.dirname(LEVEL_FILE);
|
|
6798
|
+
if (!fs18.existsSync(dir)) fs18.mkdirSync(dir, { recursive: true });
|
|
6799
|
+
fs18.writeFileSync(LEVEL_FILE, JSON.stringify(levels, null, 2), "utf-8");
|
|
6417
6800
|
}
|
|
6418
6801
|
function computeLevel(activations) {
|
|
6419
6802
|
if (activations >= 50) return { level: 5, label: "Expert" };
|
|
@@ -6477,7 +6860,7 @@ async function autoTriggerSkills(userInput, mcpManager) {
|
|
|
6477
6860
|
const result = await mcpManager.callTool("skill_list", {});
|
|
6478
6861
|
const skills = JSON.parse(result);
|
|
6479
6862
|
const installed = skills.filter((s) => s.installed).map((s) => s.name);
|
|
6480
|
-
const skillsMdPath =
|
|
6863
|
+
const skillsMdPath = path18.join(os17.homedir(), ".askill", "skills.md");
|
|
6481
6864
|
const runtimeTriggers = await loadRuntimeTriggers(skillsMdPath);
|
|
6482
6865
|
if (installed.length === 0 && runtimeTriggers.size === 0) return "";
|
|
6483
6866
|
const matched = matchSkills(userInput, installed, runtimeTriggers);
|
|
@@ -7036,9 +7419,9 @@ function humanizeError(message) {
|
|
|
7036
7419
|
}
|
|
7037
7420
|
|
|
7038
7421
|
// src/hints.ts
|
|
7039
|
-
import
|
|
7040
|
-
import
|
|
7041
|
-
import
|
|
7422
|
+
import fs19 from "fs";
|
|
7423
|
+
import path19 from "path";
|
|
7424
|
+
import os18 from "os";
|
|
7042
7425
|
var HINTS = [
|
|
7043
7426
|
{
|
|
7044
7427
|
id: "eval",
|
|
@@ -7076,11 +7459,11 @@ function getHint(state, ctx) {
|
|
|
7076
7459
|
}
|
|
7077
7460
|
return null;
|
|
7078
7461
|
}
|
|
7079
|
-
var HINTS_FILE =
|
|
7462
|
+
var HINTS_FILE = path19.join(os18.homedir(), ".aman-agent", "hints-seen.json");
|
|
7080
7463
|
function loadShownHints() {
|
|
7081
7464
|
try {
|
|
7082
|
-
if (
|
|
7083
|
-
const data = JSON.parse(
|
|
7465
|
+
if (fs19.existsSync(HINTS_FILE)) {
|
|
7466
|
+
const data = JSON.parse(fs19.readFileSync(HINTS_FILE, "utf-8"));
|
|
7084
7467
|
return new Set(Array.isArray(data) ? data : []);
|
|
7085
7468
|
}
|
|
7086
7469
|
} catch {
|
|
@@ -7089,9 +7472,9 @@ function loadShownHints() {
|
|
|
7089
7472
|
}
|
|
7090
7473
|
function saveShownHints(shown) {
|
|
7091
7474
|
try {
|
|
7092
|
-
const dir =
|
|
7093
|
-
|
|
7094
|
-
|
|
7475
|
+
const dir = path19.dirname(HINTS_FILE);
|
|
7476
|
+
fs19.mkdirSync(dir, { recursive: true });
|
|
7477
|
+
fs19.writeFileSync(HINTS_FILE, JSON.stringify([...shown]), "utf-8");
|
|
7095
7478
|
} catch {
|
|
7096
7479
|
}
|
|
7097
7480
|
}
|
|
@@ -7358,9 +7741,9 @@ ${task.result}`
|
|
|
7358
7741
|
}
|
|
7359
7742
|
if (cmdResult.exportConversation) {
|
|
7360
7743
|
try {
|
|
7361
|
-
const exportDir =
|
|
7362
|
-
|
|
7363
|
-
const exportPath =
|
|
7744
|
+
const exportDir = path20.join(os19.homedir(), ".aman-agent", "exports");
|
|
7745
|
+
fs20.mkdirSync(exportDir, { recursive: true });
|
|
7746
|
+
const exportPath = path20.join(exportDir, `${sessionId}.md`);
|
|
7364
7747
|
const lines = [
|
|
7365
7748
|
`# Conversation \u2014 ${(/* @__PURE__ */ new Date()).toLocaleString()}`,
|
|
7366
7749
|
`**Model:** ${model}`,
|
|
@@ -7374,7 +7757,7 @@ ${task.result}`
|
|
|
7374
7757
|
lines.push(`${label} ${msg.content}`, "");
|
|
7375
7758
|
}
|
|
7376
7759
|
}
|
|
7377
|
-
|
|
7760
|
+
fs20.writeFileSync(exportPath, lines.join("\n"), "utf-8");
|
|
7378
7761
|
console.log(pc7.green(`Exported to ${exportPath}`));
|
|
7379
7762
|
} catch {
|
|
7380
7763
|
console.log(pc7.red("Failed to export conversation."));
|
|
@@ -7500,25 +7883,25 @@ ${knowledgeItem.content}
|
|
|
7500
7883
|
for (const match of filePathMatches) {
|
|
7501
7884
|
let filePath = match[1];
|
|
7502
7885
|
if (filePath.startsWith("~/")) {
|
|
7503
|
-
filePath =
|
|
7886
|
+
filePath = path20.join(os19.homedir(), filePath.slice(2));
|
|
7504
7887
|
}
|
|
7505
|
-
if (!
|
|
7506
|
-
const ext =
|
|
7888
|
+
if (!fs20.existsSync(filePath) || !fs20.statSync(filePath).isFile()) continue;
|
|
7889
|
+
const ext = path20.extname(filePath).toLowerCase();
|
|
7507
7890
|
if (imageExts.has(ext)) {
|
|
7508
7891
|
try {
|
|
7509
|
-
const stat =
|
|
7892
|
+
const stat = fs20.statSync(filePath);
|
|
7510
7893
|
if (stat.size > maxImageBytes) {
|
|
7511
|
-
process.stdout.write(pc7.yellow(` [skipped: ${
|
|
7894
|
+
process.stdout.write(pc7.yellow(` [skipped: ${path20.basename(filePath)} \u2014 exceeds 20MB limit]
|
|
7512
7895
|
`));
|
|
7513
7896
|
continue;
|
|
7514
7897
|
}
|
|
7515
|
-
const data =
|
|
7898
|
+
const data = fs20.readFileSync(filePath).toString("base64");
|
|
7516
7899
|
const mediaType = mimeMap[ext] || "image/png";
|
|
7517
7900
|
imageBlocks.push({
|
|
7518
7901
|
type: "image",
|
|
7519
7902
|
source: { type: "base64", media_type: mediaType, data }
|
|
7520
7903
|
});
|
|
7521
|
-
process.stdout.write(pc7.dim(` [attached image: ${
|
|
7904
|
+
process.stdout.write(pc7.dim(` [attached image: ${path20.basename(filePath)} (${(stat.size / 1024).toFixed(1)}KB)]
|
|
7522
7905
|
`));
|
|
7523
7906
|
} catch {
|
|
7524
7907
|
process.stdout.write(pc7.dim(` [could not read image: ${filePath}]
|
|
@@ -7526,7 +7909,7 @@ ${knowledgeItem.content}
|
|
|
7526
7909
|
}
|
|
7527
7910
|
} else if (textExts.has(ext) || ext === "") {
|
|
7528
7911
|
try {
|
|
7529
|
-
const content =
|
|
7912
|
+
const content = fs20.readFileSync(filePath, "utf-8");
|
|
7530
7913
|
const maxChars = 5e4;
|
|
7531
7914
|
const trimmed = content.length > maxChars ? content.slice(0, maxChars) + `
|
|
7532
7915
|
|
|
@@ -7536,7 +7919,7 @@ ${knowledgeItem.content}
|
|
|
7536
7919
|
<file path="${filePath}" size="${content.length} chars">
|
|
7537
7920
|
${trimmed}
|
|
7538
7921
|
</file>`;
|
|
7539
|
-
process.stdout.write(pc7.dim(` [attached: ${
|
|
7922
|
+
process.stdout.write(pc7.dim(` [attached: ${path20.basename(filePath)} (${(content.length / 1024).toFixed(1)}KB)]
|
|
7540
7923
|
`));
|
|
7541
7924
|
} catch {
|
|
7542
7925
|
process.stdout.write(pc7.dim(` [could not read: ${filePath}]
|
|
@@ -7545,7 +7928,7 @@ ${trimmed}
|
|
|
7545
7928
|
} else if (docExts.has(ext)) {
|
|
7546
7929
|
if (mcpManager) {
|
|
7547
7930
|
try {
|
|
7548
|
-
process.stdout.write(pc7.dim(` [converting: ${
|
|
7931
|
+
process.stdout.write(pc7.dim(` [converting: ${path20.basename(filePath)}...]
|
|
7549
7932
|
`));
|
|
7550
7933
|
const converted = await mcpManager.callTool("doc_convert", { path: filePath });
|
|
7551
7934
|
if (converted && !converted.startsWith("Error") && !converted.includes("Could not convert")) {
|
|
@@ -7554,7 +7937,7 @@ ${trimmed}
|
|
|
7554
7937
|
<file path="${filePath}" format="${ext}">
|
|
7555
7938
|
${converted.slice(0, 5e4)}
|
|
7556
7939
|
</file>`;
|
|
7557
|
-
process.stdout.write(pc7.dim(` [attached: ${
|
|
7940
|
+
process.stdout.write(pc7.dim(` [attached: ${path20.basename(filePath)} (converted from ${ext})]
|
|
7558
7941
|
`));
|
|
7559
7942
|
} else {
|
|
7560
7943
|
textContent += `
|
|
@@ -7566,7 +7949,7 @@ ${converted}
|
|
|
7566
7949
|
`));
|
|
7567
7950
|
}
|
|
7568
7951
|
} catch {
|
|
7569
|
-
process.stdout.write(pc7.dim(` [could not convert: ${
|
|
7952
|
+
process.stdout.write(pc7.dim(` [could not convert: ${path20.basename(filePath)}]
|
|
7570
7953
|
`));
|
|
7571
7954
|
}
|
|
7572
7955
|
} else {
|
|
@@ -7870,7 +8253,7 @@ ${result2.response}` : `[${input2.profile}] failed: ${result2.error}`;
|
|
|
7870
8253
|
}
|
|
7871
8254
|
if (hooksConfig?.featureHints) {
|
|
7872
8255
|
hintState.turnCount++;
|
|
7873
|
-
const hasWorkflows =
|
|
8256
|
+
const hasWorkflows = fs20.existsSync(path20.join(os19.homedir(), ".aflow", "flow.md"));
|
|
7874
8257
|
const memoryCount = memoryTokens > 0 ? Math.floor(memoryTokens / 5) : 0;
|
|
7875
8258
|
const hint = getHint(hintState, { hasWorkflows, memoryCount });
|
|
7876
8259
|
if (hint) {
|
|
@@ -7916,9 +8299,9 @@ async function saveConversationToMemory(messages, sessionId) {
|
|
|
7916
8299
|
}
|
|
7917
8300
|
|
|
7918
8301
|
// src/index.ts
|
|
7919
|
-
import
|
|
7920
|
-
import
|
|
7921
|
-
import
|
|
8302
|
+
import fs21 from "fs";
|
|
8303
|
+
import path21 from "path";
|
|
8304
|
+
import os20 from "os";
|
|
7922
8305
|
|
|
7923
8306
|
// src/presets.ts
|
|
7924
8307
|
var PRESETS = {
|
|
@@ -8027,9 +8410,9 @@ ${wfSections}`;
|
|
|
8027
8410
|
|
|
8028
8411
|
// src/index.ts
|
|
8029
8412
|
async function autoDetectConfig() {
|
|
8030
|
-
const reconfigMarker =
|
|
8031
|
-
if (
|
|
8032
|
-
|
|
8413
|
+
const reconfigMarker = path21.join(os20.homedir(), ".aman-agent", ".reconfig");
|
|
8414
|
+
if (fs21.existsSync(reconfigMarker)) {
|
|
8415
|
+
fs21.unlinkSync(reconfigMarker);
|
|
8033
8416
|
return null;
|
|
8034
8417
|
}
|
|
8035
8418
|
const anthropicKey = process.env.ANTHROPIC_API_KEY;
|
|
@@ -8058,11 +8441,11 @@ async function autoDetectConfig() {
|
|
|
8058
8441
|
return null;
|
|
8059
8442
|
}
|
|
8060
8443
|
function bootstrapEcosystem() {
|
|
8061
|
-
const home2 =
|
|
8062
|
-
const corePath =
|
|
8063
|
-
if (
|
|
8064
|
-
|
|
8065
|
-
|
|
8444
|
+
const home2 = os20.homedir();
|
|
8445
|
+
const corePath = path21.join(home2, ".acore", "core.md");
|
|
8446
|
+
if (fs21.existsSync(corePath)) return false;
|
|
8447
|
+
fs21.mkdirSync(path21.join(home2, ".acore"), { recursive: true });
|
|
8448
|
+
fs21.writeFileSync(corePath, [
|
|
8066
8449
|
"# Aman",
|
|
8067
8450
|
"",
|
|
8068
8451
|
"## Personality",
|
|
@@ -8074,11 +8457,11 @@ function bootstrapEcosystem() {
|
|
|
8074
8457
|
"## Session",
|
|
8075
8458
|
"_New companion \u2014 no prior sessions._"
|
|
8076
8459
|
].join("\n"), "utf-8");
|
|
8077
|
-
const rulesDir =
|
|
8078
|
-
const rulesPath =
|
|
8079
|
-
if (!
|
|
8080
|
-
|
|
8081
|
-
|
|
8460
|
+
const rulesDir = path21.join(home2, ".arules");
|
|
8461
|
+
const rulesPath = path21.join(rulesDir, "rules.md");
|
|
8462
|
+
if (!fs21.existsSync(rulesPath)) {
|
|
8463
|
+
fs21.mkdirSync(rulesDir, { recursive: true });
|
|
8464
|
+
fs21.writeFileSync(rulesPath, [
|
|
8082
8465
|
"# Guardrails",
|
|
8083
8466
|
"",
|
|
8084
8467
|
"## safety",
|
|
@@ -8090,22 +8473,22 @@ function bootstrapEcosystem() {
|
|
|
8090
8473
|
"- Respect the user's preferences stored in memory"
|
|
8091
8474
|
].join("\n"), "utf-8");
|
|
8092
8475
|
}
|
|
8093
|
-
const flowDir =
|
|
8094
|
-
const flowPath =
|
|
8095
|
-
if (!
|
|
8096
|
-
|
|
8097
|
-
|
|
8476
|
+
const flowDir = path21.join(home2, ".aflow");
|
|
8477
|
+
const flowPath = path21.join(flowDir, "flow.md");
|
|
8478
|
+
if (!fs21.existsSync(flowPath)) {
|
|
8479
|
+
fs21.mkdirSync(flowDir, { recursive: true });
|
|
8480
|
+
fs21.writeFileSync(flowPath, "# Workflows\n\n_No workflows defined yet. Use /workflows add to create one._\n", "utf-8");
|
|
8098
8481
|
}
|
|
8099
|
-
const skillDir =
|
|
8100
|
-
const skillPath =
|
|
8101
|
-
if (!
|
|
8102
|
-
|
|
8103
|
-
|
|
8482
|
+
const skillDir = path21.join(home2, ".askill");
|
|
8483
|
+
const skillPath = path21.join(skillDir, "skills.md");
|
|
8484
|
+
if (!fs21.existsSync(skillPath)) {
|
|
8485
|
+
fs21.mkdirSync(skillDir, { recursive: true });
|
|
8486
|
+
fs21.writeFileSync(skillPath, "# Skills\n\n_No skills installed yet. Use /skills install to add domain expertise._\n", "utf-8");
|
|
8104
8487
|
}
|
|
8105
8488
|
return true;
|
|
8106
8489
|
}
|
|
8107
8490
|
var program = new Command();
|
|
8108
|
-
program.name("aman-agent").description("Your AI companion, running locally").version("0.
|
|
8491
|
+
program.name("aman-agent").description("Your AI companion, running locally").version("0.27.0").option("--model <model>", "Override LLM model").option("--budget <tokens>", "Token budget for system prompt (default: 8000)", parseInt).option("--profile <name>", "Use a specific agent profile (e.g., coder, writer, researcher)").action(async (options) => {
|
|
8109
8492
|
p3.intro(pc8.bold("aman agent") + pc8.dim(" \u2014 your AI companion"));
|
|
8110
8493
|
let config = loadConfig();
|
|
8111
8494
|
if (!config) {
|
|
@@ -8457,19 +8840,19 @@ program.command("init").description("Set up your AI companion with a guided wiza
|
|
|
8457
8840
|
});
|
|
8458
8841
|
if (p3.isCancel(preset)) process.exit(0);
|
|
8459
8842
|
const result = applyPreset(preset, name || "Aman");
|
|
8460
|
-
const home2 =
|
|
8461
|
-
|
|
8462
|
-
|
|
8843
|
+
const home2 = os20.homedir();
|
|
8844
|
+
fs21.mkdirSync(path21.join(home2, ".acore"), { recursive: true });
|
|
8845
|
+
fs21.writeFileSync(path21.join(home2, ".acore", "core.md"), result.coreMd, "utf-8");
|
|
8463
8846
|
p3.log.success(`Identity created \u2014 ${PRESETS[preset].identity.personality.split(".")[0].toLowerCase()}`);
|
|
8464
8847
|
if (result.rulesMd) {
|
|
8465
|
-
|
|
8466
|
-
|
|
8848
|
+
fs21.mkdirSync(path21.join(home2, ".arules"), { recursive: true });
|
|
8849
|
+
fs21.writeFileSync(path21.join(home2, ".arules", "rules.md"), result.rulesMd, "utf-8");
|
|
8467
8850
|
const ruleCount = (result.rulesMd.match(/^- /gm) || []).length;
|
|
8468
8851
|
p3.log.success(`${ruleCount} rules set`);
|
|
8469
8852
|
}
|
|
8470
8853
|
if (result.flowMd) {
|
|
8471
|
-
|
|
8472
|
-
|
|
8854
|
+
fs21.mkdirSync(path21.join(home2, ".aflow"), { recursive: true });
|
|
8855
|
+
fs21.writeFileSync(path21.join(home2, ".aflow", "flow.md"), result.flowMd, "utf-8");
|
|
8473
8856
|
const wfCount = (result.flowMd.match(/^## /gm) || []).length;
|
|
8474
8857
|
p3.log.success(`${wfCount} workflow${wfCount > 1 ? "s" : ""} added`);
|
|
8475
8858
|
}
|