helixevo 0.2.40 → 0.3.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/CHANGELOG.md +31 -0
- package/README.md +19 -6
- package/dashboard/app/commands/page.tsx +28 -4
- package/dashboard/app/evolution/page.tsx +58 -37
- package/dashboard/app/guide/page.tsx +37 -3
- package/dashboard/app/network/client.tsx +125 -1
- package/dashboard/app/network/page.tsx +3 -1
- package/dashboard/app/page.tsx +57 -1
- package/dashboard/app/projects/client.tsx +21 -2
- package/dashboard/app/projects/page.tsx +29 -2
- package/dashboard/app/research/client.tsx +67 -1
- package/dashboard/app/research/page.tsx +3 -2
- package/dashboard/lib/data.ts +443 -1
- package/dist/cli.js +715 -223
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -9174,9 +9174,240 @@ var init_skills = __esm(() => {
|
|
|
9174
9174
|
FRONTMATTER_RE = /^---\n([\s\S]*?)\n---\n([\s\S]*)$/;
|
|
9175
9175
|
});
|
|
9176
9176
|
|
|
9177
|
+
// src/ontology/entities.ts
|
|
9178
|
+
var ONTOLOGY_KERNEL_ENTITY_NAMES;
|
|
9179
|
+
var init_entities = __esm(() => {
|
|
9180
|
+
ONTOLOGY_KERNEL_ENTITY_NAMES = [
|
|
9181
|
+
"ProjectRecord",
|
|
9182
|
+
"SessionRecord",
|
|
9183
|
+
"TaskRecord",
|
|
9184
|
+
"FailureRecord",
|
|
9185
|
+
"PressureSignal",
|
|
9186
|
+
"Capability",
|
|
9187
|
+
"SkillNode",
|
|
9188
|
+
"SkillRelation",
|
|
9189
|
+
"ActivationEvent",
|
|
9190
|
+
"MutationProposal",
|
|
9191
|
+
"TopologyChange",
|
|
9192
|
+
"EvidenceArtifact",
|
|
9193
|
+
"EvaluationResult",
|
|
9194
|
+
"TransferEvent",
|
|
9195
|
+
"GovernanceMode",
|
|
9196
|
+
"HealthMetric",
|
|
9197
|
+
"LineageRecord",
|
|
9198
|
+
"OntologyConcept",
|
|
9199
|
+
"OntologyChangeEvent"
|
|
9200
|
+
];
|
|
9201
|
+
});
|
|
9202
|
+
|
|
9203
|
+
// src/ontology/relations.ts
|
|
9204
|
+
var ONTOLOGY_RELATION_FAMILIES;
|
|
9205
|
+
var init_relations = __esm(() => {
|
|
9206
|
+
ONTOLOGY_RELATION_FAMILIES = [
|
|
9207
|
+
"belongs_to",
|
|
9208
|
+
"derived_from",
|
|
9209
|
+
"replaced_by",
|
|
9210
|
+
"parent_of",
|
|
9211
|
+
"child_of",
|
|
9212
|
+
"specializes",
|
|
9213
|
+
"generalizes_from",
|
|
9214
|
+
"depends_on",
|
|
9215
|
+
"enhances",
|
|
9216
|
+
"conflicts_with",
|
|
9217
|
+
"co_evolves_with",
|
|
9218
|
+
"covers",
|
|
9219
|
+
"activated_for",
|
|
9220
|
+
"suppressed_by",
|
|
9221
|
+
"contributed_to",
|
|
9222
|
+
"competed_with",
|
|
9223
|
+
"triggered_by",
|
|
9224
|
+
"validated_by",
|
|
9225
|
+
"contradicted_by",
|
|
9226
|
+
"survived_in",
|
|
9227
|
+
"requires_review",
|
|
9228
|
+
"proposed_due_to",
|
|
9229
|
+
"benefits",
|
|
9230
|
+
"transferred_to",
|
|
9231
|
+
"refined_by",
|
|
9232
|
+
"promoted_from",
|
|
9233
|
+
"executed_under",
|
|
9234
|
+
"deferred_by",
|
|
9235
|
+
"prioritized_by",
|
|
9236
|
+
"locked_by",
|
|
9237
|
+
"measures",
|
|
9238
|
+
"signals_weakness_in",
|
|
9239
|
+
"suggests_repair_for"
|
|
9240
|
+
];
|
|
9241
|
+
});
|
|
9242
|
+
|
|
9243
|
+
// src/ontology/operations.ts
|
|
9244
|
+
var SKILL_OPERATIONS, TOPOLOGY_OPERATIONS, ONTOLOGY_OPERATIONS, GOVERNANCE_OPERATIONS, ONTOLOGY_MUTATION_OPERATIONS, ONTOLOGY_ALL_OPERATIONS;
|
|
9245
|
+
var init_operations = __esm(() => {
|
|
9246
|
+
SKILL_OPERATIONS = [
|
|
9247
|
+
"create_skill",
|
|
9248
|
+
"edit_skill",
|
|
9249
|
+
"specialize_skill",
|
|
9250
|
+
"generalize_skill",
|
|
9251
|
+
"promote_skill",
|
|
9252
|
+
"demote_skill",
|
|
9253
|
+
"retire_skill"
|
|
9254
|
+
];
|
|
9255
|
+
TOPOLOGY_OPERATIONS = [
|
|
9256
|
+
"merge_skills",
|
|
9257
|
+
"split_skill",
|
|
9258
|
+
"rewire_relation",
|
|
9259
|
+
"prune_branch",
|
|
9260
|
+
"consolidate_cluster"
|
|
9261
|
+
];
|
|
9262
|
+
ONTOLOGY_OPERATIONS = [
|
|
9263
|
+
"hypothesize_concept",
|
|
9264
|
+
"promote_concept",
|
|
9265
|
+
"merge_concepts",
|
|
9266
|
+
"split_concept",
|
|
9267
|
+
"deprecate_concept",
|
|
9268
|
+
"refine_relation_subtype",
|
|
9269
|
+
"add_invariant",
|
|
9270
|
+
"migrate_mapping"
|
|
9271
|
+
];
|
|
9272
|
+
GOVERNANCE_OPERATIONS = [
|
|
9273
|
+
"change_mode",
|
|
9274
|
+
"adjust_plasticity_regime",
|
|
9275
|
+
"allocate_attention",
|
|
9276
|
+
"defer_change",
|
|
9277
|
+
"require_review"
|
|
9278
|
+
];
|
|
9279
|
+
ONTOLOGY_MUTATION_OPERATIONS = [
|
|
9280
|
+
...SKILL_OPERATIONS,
|
|
9281
|
+
...TOPOLOGY_OPERATIONS
|
|
9282
|
+
];
|
|
9283
|
+
ONTOLOGY_ALL_OPERATIONS = [
|
|
9284
|
+
...SKILL_OPERATIONS,
|
|
9285
|
+
...TOPOLOGY_OPERATIONS,
|
|
9286
|
+
...ONTOLOGY_OPERATIONS,
|
|
9287
|
+
...GOVERNANCE_OPERATIONS
|
|
9288
|
+
];
|
|
9289
|
+
});
|
|
9290
|
+
|
|
9291
|
+
// src/ontology/invariants.ts
|
|
9292
|
+
var ONTOLOGY_INVARIANTS;
|
|
9293
|
+
var init_invariants = __esm(() => {
|
|
9294
|
+
ONTOLOGY_INVARIANTS = [
|
|
9295
|
+
{
|
|
9296
|
+
id: "accepted-change-requires-evidence",
|
|
9297
|
+
description: "Every accepted change must reference evidence."
|
|
9298
|
+
},
|
|
9299
|
+
{
|
|
9300
|
+
id: "specialist-requires-local-context",
|
|
9301
|
+
description: "Every specialist skill must be linked to a project or local context."
|
|
9302
|
+
},
|
|
9303
|
+
{
|
|
9304
|
+
id: "promotion-requires-repeated-evidence",
|
|
9305
|
+
description: "Every promotion toward generalist intelligence must cite repeated cross-project or repeated-context evidence."
|
|
9306
|
+
},
|
|
9307
|
+
{
|
|
9308
|
+
id: "relation-requires-family-and-confidence",
|
|
9309
|
+
description: "Every skill relation must declare a relation family and confidence source."
|
|
9310
|
+
},
|
|
9311
|
+
{
|
|
9312
|
+
id: "topology-change-preserves-lineage",
|
|
9313
|
+
description: "Every topology change must preserve or explicitly rewrite lineage."
|
|
9314
|
+
},
|
|
9315
|
+
{
|
|
9316
|
+
id: "deprecated-state-remains-recoverable",
|
|
9317
|
+
description: "Every deprecated skill or concept must remain recoverable through lineage."
|
|
9318
|
+
},
|
|
9319
|
+
{
|
|
9320
|
+
id: "ontology-promotion-requires-migration",
|
|
9321
|
+
description: "Every ontology promotion must include a migration mapping."
|
|
9322
|
+
},
|
|
9323
|
+
{
|
|
9324
|
+
id: "frontier-concepts-stay-provisional",
|
|
9325
|
+
description: "Every frontier concept remains provisional until promoted through review."
|
|
9326
|
+
},
|
|
9327
|
+
{
|
|
9328
|
+
id: "transfer-requires-source-and-target",
|
|
9329
|
+
description: "Every transfer claim must identify source and target contexts."
|
|
9330
|
+
},
|
|
9331
|
+
{
|
|
9332
|
+
id: "high-risk-topology-change-requires-validation",
|
|
9333
|
+
description: "Every accepted high-risk topology change must have replay or equivalent validation."
|
|
9334
|
+
}
|
|
9335
|
+
];
|
|
9336
|
+
});
|
|
9337
|
+
|
|
9338
|
+
// src/ontology/events.ts
|
|
9339
|
+
var ONTOLOGY_EVENT_TYPES;
|
|
9340
|
+
var init_events = __esm(() => {
|
|
9341
|
+
ONTOLOGY_EVENT_TYPES = [
|
|
9342
|
+
"failure_captured",
|
|
9343
|
+
"pressure_detected",
|
|
9344
|
+
"skill_activated",
|
|
9345
|
+
"skill_suppressed",
|
|
9346
|
+
"capability_gap_detected",
|
|
9347
|
+
"mutation_proposed",
|
|
9348
|
+
"mutation_accepted",
|
|
9349
|
+
"mutation_rejected",
|
|
9350
|
+
"topology_changed",
|
|
9351
|
+
"transfer_realized",
|
|
9352
|
+
"replay_completed",
|
|
9353
|
+
"regression_completed",
|
|
9354
|
+
"canary_completed",
|
|
9355
|
+
"rollback_triggered",
|
|
9356
|
+
"concept_hypothesized",
|
|
9357
|
+
"concept_promoted",
|
|
9358
|
+
"concept_rejected",
|
|
9359
|
+
"concept_merged",
|
|
9360
|
+
"concept_split",
|
|
9361
|
+
"governance_changed"
|
|
9362
|
+
];
|
|
9363
|
+
});
|
|
9364
|
+
|
|
9365
|
+
// src/ontology/spec.ts
|
|
9366
|
+
var ONTOLOGY_SPEC_VERSION = "0.1.0", ONTOLOGY_KERNEL_PILLARS, ONTOLOGY_LAYERS, ONTOLOGY_V0_SPEC;
|
|
9367
|
+
var init_spec = __esm(() => {
|
|
9368
|
+
init_entities();
|
|
9369
|
+
init_events();
|
|
9370
|
+
init_invariants();
|
|
9371
|
+
init_operations();
|
|
9372
|
+
init_relations();
|
|
9373
|
+
ONTOLOGY_KERNEL_PILLARS = [
|
|
9374
|
+
"Operational World",
|
|
9375
|
+
"Perception / Pressure",
|
|
9376
|
+
"Working Memory / Activation",
|
|
9377
|
+
"Long-Term Memory",
|
|
9378
|
+
"Plasticity / Topology",
|
|
9379
|
+
"Evidence / Immune System",
|
|
9380
|
+
"Executive / Governance",
|
|
9381
|
+
"Metacognition / Health",
|
|
9382
|
+
"Time / Lineage"
|
|
9383
|
+
];
|
|
9384
|
+
ONTOLOGY_LAYERS = ["kernel", "extension", "frontier", "vocabulary"];
|
|
9385
|
+
ONTOLOGY_V0_SPEC = {
|
|
9386
|
+
version: ONTOLOGY_SPEC_VERSION,
|
|
9387
|
+
pillars: [...ONTOLOGY_KERNEL_PILLARS],
|
|
9388
|
+
layers: [...ONTOLOGY_LAYERS],
|
|
9389
|
+
entityNames: [...ONTOLOGY_KERNEL_ENTITY_NAMES],
|
|
9390
|
+
relationFamilies: [...ONTOLOGY_RELATION_FAMILIES],
|
|
9391
|
+
mutationOperations: [...ONTOLOGY_MUTATION_OPERATIONS],
|
|
9392
|
+
operations: [...ONTOLOGY_ALL_OPERATIONS],
|
|
9393
|
+
invariantIds: ONTOLOGY_INVARIANTS.map((invariant) => invariant.id),
|
|
9394
|
+
eventTypes: [...ONTOLOGY_EVENT_TYPES]
|
|
9395
|
+
};
|
|
9396
|
+
});
|
|
9397
|
+
|
|
9398
|
+
// src/ontology/index.ts
|
|
9399
|
+
var init_ontology = __esm(() => {
|
|
9400
|
+
init_entities();
|
|
9401
|
+
init_relations();
|
|
9402
|
+
init_operations();
|
|
9403
|
+
init_invariants();
|
|
9404
|
+
init_events();
|
|
9405
|
+
init_spec();
|
|
9406
|
+
});
|
|
9407
|
+
|
|
9177
9408
|
// src/utils/data.ts
|
|
9178
|
-
import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, appendFileSync, existsSync as existsSync3 } from "node:fs";
|
|
9179
|
-
import { dirname } from "node:path";
|
|
9409
|
+
import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, appendFileSync, existsSync as existsSync3, readdirSync as readdirSync2 } from "node:fs";
|
|
9410
|
+
import { dirname, join as join3 } from "node:path";
|
|
9180
9411
|
function readJsonl(filename) {
|
|
9181
9412
|
const path = getDataPath(filename);
|
|
9182
9413
|
if (!existsSync3(path))
|
|
@@ -9246,19 +9477,45 @@ function loadSkillGraph() {
|
|
|
9246
9477
|
function saveSkillGraph(graph) {
|
|
9247
9478
|
writeJson("skill-graph.json", graph);
|
|
9248
9479
|
}
|
|
9480
|
+
function appendEvolutionArtifact(artifact) {
|
|
9481
|
+
appendJsonl("evolution-artifacts.jsonl", artifact);
|
|
9482
|
+
}
|
|
9483
|
+
function appendActivationTrace(trace) {
|
|
9484
|
+
appendJsonl("activation-traces.jsonl", trace);
|
|
9485
|
+
}
|
|
9486
|
+
function appendPressureSignal(signal) {
|
|
9487
|
+
appendJsonl("pressure-signals.jsonl", signal);
|
|
9488
|
+
}
|
|
9249
9489
|
var init_data = __esm(() => {
|
|
9490
|
+
init_ontology();
|
|
9250
9491
|
init_config();
|
|
9251
9492
|
});
|
|
9252
9493
|
|
|
9253
9494
|
// src/utils/llm.ts
|
|
9254
9495
|
import { spawn } from "node:child_process";
|
|
9255
|
-
function
|
|
9496
|
+
function buildClaudeEnv({ dropOauthToken }) {
|
|
9497
|
+
const env = { ...process.env };
|
|
9498
|
+
if (dropOauthToken) {
|
|
9499
|
+
delete env.CLAUDE_CODE_OAUTH_TOKEN;
|
|
9500
|
+
}
|
|
9501
|
+
return env;
|
|
9502
|
+
}
|
|
9503
|
+
function runClaudeOnce(prompt, args, env) {
|
|
9256
9504
|
return new Promise((resolve, reject) => {
|
|
9257
9505
|
const proc = spawn("claude", args, {
|
|
9258
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
9506
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
9507
|
+
env
|
|
9259
9508
|
});
|
|
9260
9509
|
let stdout = "";
|
|
9261
9510
|
let stderr = "";
|
|
9511
|
+
let settled = false;
|
|
9512
|
+
const timeout = setTimeout(() => {
|
|
9513
|
+
proc.kill();
|
|
9514
|
+
if (!settled) {
|
|
9515
|
+
settled = true;
|
|
9516
|
+
reject(new Error("claude call timed out after 180s"));
|
|
9517
|
+
}
|
|
9518
|
+
}, 180000);
|
|
9262
9519
|
proc.stdout.on("data", (data) => {
|
|
9263
9520
|
stdout += data.toString();
|
|
9264
9521
|
});
|
|
@@ -9266,23 +9523,42 @@ function runClaude(prompt, args) {
|
|
|
9266
9523
|
stderr += data.toString();
|
|
9267
9524
|
});
|
|
9268
9525
|
proc.on("close", (code) => {
|
|
9526
|
+
clearTimeout(timeout);
|
|
9527
|
+
if (settled)
|
|
9528
|
+
return;
|
|
9529
|
+
settled = true;
|
|
9269
9530
|
if (code !== 0) {
|
|
9270
|
-
|
|
9531
|
+
const output = (stderr || stdout).slice(0, 500);
|
|
9532
|
+
reject(new Error(`claude exited with code ${code}: ${output}`));
|
|
9271
9533
|
} else {
|
|
9272
9534
|
resolve(stdout.trim());
|
|
9273
9535
|
}
|
|
9274
9536
|
});
|
|
9275
9537
|
proc.on("error", (err) => {
|
|
9538
|
+
clearTimeout(timeout);
|
|
9539
|
+
if (settled)
|
|
9540
|
+
return;
|
|
9541
|
+
settled = true;
|
|
9276
9542
|
reject(new Error(`Failed to spawn claude: ${err.message}`));
|
|
9277
9543
|
});
|
|
9278
9544
|
proc.stdin.write(prompt);
|
|
9279
9545
|
proc.stdin.end();
|
|
9280
|
-
setTimeout(() => {
|
|
9281
|
-
proc.kill();
|
|
9282
|
-
reject(new Error("claude call timed out after 180s"));
|
|
9283
|
-
}, 180000);
|
|
9284
9546
|
});
|
|
9285
9547
|
}
|
|
9548
|
+
function isRetryableClaudeAuthError(error) {
|
|
9549
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
9550
|
+
return CLAUDE_AUTH_ERROR_PATTERNS.some((pattern) => message.includes(pattern));
|
|
9551
|
+
}
|
|
9552
|
+
async function runClaude(prompt, args) {
|
|
9553
|
+
try {
|
|
9554
|
+
return await runClaudeOnce(prompt, args, buildClaudeEnv({ dropOauthToken: false }));
|
|
9555
|
+
} catch (error) {
|
|
9556
|
+
if (!process.env.CLAUDE_CODE_OAUTH_TOKEN || !isRetryableClaudeAuthError(error)) {
|
|
9557
|
+
throw error;
|
|
9558
|
+
}
|
|
9559
|
+
return runClaudeOnce(prompt, args, buildClaudeEnv({ dropOauthToken: true }));
|
|
9560
|
+
}
|
|
9561
|
+
}
|
|
9286
9562
|
async function chat(options) {
|
|
9287
9563
|
const config = loadConfig();
|
|
9288
9564
|
const model = options.model ?? config.model;
|
|
@@ -9334,8 +9610,14 @@ async function searchWeb(query) {
|
|
|
9334
9610
|
];
|
|
9335
9611
|
return runClaude(query, args);
|
|
9336
9612
|
}
|
|
9613
|
+
var CLAUDE_AUTH_ERROR_PATTERNS;
|
|
9337
9614
|
var init_llm = __esm(() => {
|
|
9338
9615
|
init_config();
|
|
9616
|
+
CLAUDE_AUTH_ERROR_PATTERNS = [
|
|
9617
|
+
"OAuth token has expired",
|
|
9618
|
+
"authentication_error",
|
|
9619
|
+
"Failed to authenticate"
|
|
9620
|
+
];
|
|
9339
9621
|
});
|
|
9340
9622
|
|
|
9341
9623
|
// src/core/network-health.ts
|
|
@@ -9576,7 +9858,7 @@ init_config();
|
|
|
9576
9858
|
init_skills();
|
|
9577
9859
|
init_data();
|
|
9578
9860
|
init_llm();
|
|
9579
|
-
import { join as
|
|
9861
|
+
import { join as join5 } from "node:path";
|
|
9580
9862
|
import { homedir as homedir2 } from "node:os";
|
|
9581
9863
|
import { existsSync as existsSync4, cpSync } from "node:fs";
|
|
9582
9864
|
|
|
@@ -9607,10 +9889,10 @@ Return JSON:
|
|
|
9607
9889
|
|
|
9608
9890
|
// src/version.ts
|
|
9609
9891
|
import { createRequire as createRequire2 } from "node:module";
|
|
9610
|
-
import { join as
|
|
9892
|
+
import { join as join4, dirname as dirname2 } from "node:path";
|
|
9611
9893
|
import { fileURLToPath } from "node:url";
|
|
9612
9894
|
var require2 = createRequire2(import.meta.url);
|
|
9613
|
-
var pkg = require2(
|
|
9895
|
+
var pkg = require2(join4(dirname2(fileURLToPath(import.meta.url)), "..", "package.json"));
|
|
9614
9896
|
var VERSION = pkg.version;
|
|
9615
9897
|
|
|
9616
9898
|
// src/commands/init.ts
|
|
@@ -9621,22 +9903,22 @@ async function initCommand(options) {
|
|
|
9621
9903
|
const generalDir = getGeneralSkillsPath();
|
|
9622
9904
|
ensureDir(sgDir);
|
|
9623
9905
|
ensureDir(generalDir);
|
|
9624
|
-
if (!existsSync4(
|
|
9906
|
+
if (!existsSync4(join5(sgDir, "config.json"))) {
|
|
9625
9907
|
saveConfig(DEFAULT_CONFIG);
|
|
9626
9908
|
console.log(" ✓ Created config.json");
|
|
9627
9909
|
}
|
|
9628
9910
|
const defaultPaths = [
|
|
9629
|
-
|
|
9630
|
-
|
|
9911
|
+
join5(homedir2(), ".agents", "skills"),
|
|
9912
|
+
join5(homedir2(), ".craft-agent", "workspaces")
|
|
9631
9913
|
];
|
|
9632
9914
|
const scanPaths = options.skillsPaths ?? defaultPaths;
|
|
9633
9915
|
const expandedPaths = [];
|
|
9634
9916
|
for (const p of scanPaths) {
|
|
9635
9917
|
if (p.includes("workspaces") && existsSync4(p)) {
|
|
9636
|
-
const { readdirSync:
|
|
9637
|
-
const workspaces =
|
|
9918
|
+
const { readdirSync: readdirSync3 } = await import("node:fs");
|
|
9919
|
+
const workspaces = readdirSync3(p, { withFileTypes: true }).filter((d) => d.isDirectory() && !d.name.startsWith("."));
|
|
9638
9920
|
for (const ws of workspaces) {
|
|
9639
|
-
const skillsDir =
|
|
9921
|
+
const skillsDir = join5(p, ws.name, "skills");
|
|
9640
9922
|
if (existsSync4(skillsDir))
|
|
9641
9923
|
expandedPaths.push(skillsDir);
|
|
9642
9924
|
}
|
|
@@ -9649,7 +9931,7 @@ async function initCommand(options) {
|
|
|
9649
9931
|
`);
|
|
9650
9932
|
let imported = 0;
|
|
9651
9933
|
for (const skill of existingSkills) {
|
|
9652
|
-
const targetDir =
|
|
9934
|
+
const targetDir = join5(generalDir, skill.slug);
|
|
9653
9935
|
if (existsSync4(targetDir)) {
|
|
9654
9936
|
console.log(` → ${skill.slug}: already exists, skipping`);
|
|
9655
9937
|
continue;
|
|
@@ -9747,19 +10029,57 @@ async function captureCommand(sessionPath, options) {
|
|
|
9747
10029
|
}
|
|
9748
10030
|
const project = options.project ?? output.project;
|
|
9749
10031
|
for (const f of output.failures) {
|
|
10032
|
+
const timestamp = new Date().toISOString();
|
|
10033
|
+
const failureId = `f_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
10034
|
+
const activationTraceId = `activation_${failureId}`;
|
|
10035
|
+
const pressureSignalId = `pressure_${failureId}`;
|
|
9750
10036
|
const record = {
|
|
9751
|
-
id:
|
|
10037
|
+
id: failureId,
|
|
9752
10038
|
sessionId,
|
|
9753
|
-
timestamp
|
|
10039
|
+
timestamp,
|
|
9754
10040
|
project,
|
|
9755
10041
|
userRequest: f.userRequest,
|
|
9756
10042
|
agentAction: f.agentAction,
|
|
9757
10043
|
correction: f.correction,
|
|
9758
10044
|
correctionType: f.correctionType,
|
|
9759
10045
|
skillsActive: f.skillsActive,
|
|
9760
|
-
skillsRelevant: f.skillsActive
|
|
10046
|
+
skillsRelevant: f.skillsActive,
|
|
10047
|
+
activationTraceId,
|
|
10048
|
+
pressureSignals: [pressureSignalId]
|
|
10049
|
+
};
|
|
10050
|
+
const activationTrace = {
|
|
10051
|
+
id: activationTraceId,
|
|
10052
|
+
timestamp,
|
|
10053
|
+
provenance: "capture-derived",
|
|
10054
|
+
sourceId: failureId,
|
|
10055
|
+
projectId: project ?? undefined,
|
|
10056
|
+
sessionId,
|
|
10057
|
+
activatedSkillIds: f.skillsActive,
|
|
10058
|
+
relevantSkillIds: f.skillsActive,
|
|
10059
|
+
reasonSummary: `${f.correctionType} correction captured from session review`,
|
|
10060
|
+
contextSummary: f.correction,
|
|
10061
|
+
relatedFailureId: failureId,
|
|
10062
|
+
traceVersion: "0.1.0"
|
|
10063
|
+
};
|
|
10064
|
+
const pressureSignal = {
|
|
10065
|
+
id: pressureSignalId,
|
|
10066
|
+
kind: `correction:${f.correctionType}`,
|
|
10067
|
+
provenance: "failure-native",
|
|
10068
|
+
sourceType: "failure",
|
|
10069
|
+
sourceId: failureId,
|
|
10070
|
+
projectId: project ?? undefined,
|
|
10071
|
+
detectedAt: timestamp,
|
|
10072
|
+
severity: f.correctionType === "manual_edit" ? 0.95 : f.correctionType === "mode_switch" ? 0.9 : f.correctionType === "retry" ? 0.72 : 0.65,
|
|
10073
|
+
priority: f.correctionType === "manual_edit" || f.correctionType === "mode_switch" ? "high" : f.correctionType === "retry" ? "medium" : "low",
|
|
10074
|
+
description: f.correction,
|
|
10075
|
+
relatedFailureId: failureId,
|
|
10076
|
+
relatedActivationTraceId: activationTraceId,
|
|
10077
|
+
skillIds: f.skillsActive,
|
|
10078
|
+
status: "open"
|
|
9761
10079
|
};
|
|
9762
10080
|
appendFailure(record);
|
|
10081
|
+
appendActivationTrace(activationTrace);
|
|
10082
|
+
appendPressureSignal(pressureSignal);
|
|
9763
10083
|
console.log(` ✓ Captured: "${f.correction.slice(0, 60)}..."`);
|
|
9764
10084
|
}
|
|
9765
10085
|
console.log(`
|
|
@@ -9805,7 +10125,7 @@ init_config();
|
|
|
9805
10125
|
init_data();
|
|
9806
10126
|
init_skills();
|
|
9807
10127
|
init_llm();
|
|
9808
|
-
import { join as
|
|
10128
|
+
import { join as join8 } from "node:path";
|
|
9809
10129
|
|
|
9810
10130
|
// src/prompts/cluster.ts
|
|
9811
10131
|
function buildClusterPrompt(failures, skills, graph) {
|
|
@@ -10216,11 +10536,11 @@ Return JSON: { "score": <number>, "reason": "<one sentence>" }`;
|
|
|
10216
10536
|
// src/core/canary.ts
|
|
10217
10537
|
init_config();
|
|
10218
10538
|
import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, existsSync as existsSync6, cpSync as cpSync2, rmSync } from "node:fs";
|
|
10219
|
-
import { join as
|
|
10220
|
-
var CANARY_DIR =
|
|
10221
|
-
var BACKUPS_DIR =
|
|
10539
|
+
import { join as join6 } from "node:path";
|
|
10540
|
+
var CANARY_DIR = join6(getHelixDir(), "canary");
|
|
10541
|
+
var BACKUPS_DIR = join6(getHelixDir(), "backups");
|
|
10222
10542
|
function getRegistryPath() {
|
|
10223
|
-
return
|
|
10543
|
+
return join6(getHelixDir(), "canary-registry.json");
|
|
10224
10544
|
}
|
|
10225
10545
|
function loadRegistry() {
|
|
10226
10546
|
const path = getRegistryPath();
|
|
@@ -10233,7 +10553,7 @@ function saveRegistry(registry) {
|
|
|
10233
10553
|
}
|
|
10234
10554
|
function backupSkill(skillPath, slug, version) {
|
|
10235
10555
|
ensureDir(BACKUPS_DIR);
|
|
10236
|
-
const backupPath =
|
|
10556
|
+
const backupPath = join6(BACKUPS_DIR, `${slug}_${version}_${Date.now()}`);
|
|
10237
10557
|
if (existsSync6(skillPath)) {
|
|
10238
10558
|
cpSync2(skillPath, backupPath, { recursive: true });
|
|
10239
10559
|
}
|
|
@@ -10315,7 +10635,7 @@ init_config();
|
|
|
10315
10635
|
init_skills();
|
|
10316
10636
|
init_data();
|
|
10317
10637
|
init_llm();
|
|
10318
|
-
import { join as
|
|
10638
|
+
import { join as join7 } from "node:path";
|
|
10319
10639
|
async function autoGeneralize(candidates, verbose = false, dryRun = false) {
|
|
10320
10640
|
const created = [];
|
|
10321
10641
|
const skipped = [];
|
|
@@ -10384,7 +10704,7 @@ Keep it focused and actionable. No filler.`
|
|
|
10384
10704
|
meta.lastEvolved = new Date().toISOString();
|
|
10385
10705
|
meta.tags = [...meta.tags ?? [], "auto-generalized"];
|
|
10386
10706
|
meta.enhances = candidate.sourceSkills;
|
|
10387
|
-
const skillDir =
|
|
10707
|
+
const skillDir = join7(getGeneralSkillsPath(), candidate.suggestedName);
|
|
10388
10708
|
writeSkill(skillDir, meta, content);
|
|
10389
10709
|
created.push(candidate.suggestedName);
|
|
10390
10710
|
console.log(` ✓ Created: ${candidate.suggestedName} (domain layer)`);
|
|
@@ -10489,8 +10809,10 @@ async function evolveCommand(options) {
|
|
|
10489
10809
|
console.log();
|
|
10490
10810
|
}
|
|
10491
10811
|
const generation = getCurrentGeneration() + 1;
|
|
10812
|
+
const iterationId = generateIterationId();
|
|
10492
10813
|
const proposals = [];
|
|
10493
10814
|
const failureClusters = [];
|
|
10815
|
+
const artifacts = [];
|
|
10494
10816
|
let proposalCount = 0;
|
|
10495
10817
|
for (const cluster of clusters.clusters) {
|
|
10496
10818
|
if (proposalCount >= maxProposals)
|
|
@@ -10589,10 +10911,40 @@ async function evolveCommand(options) {
|
|
|
10589
10911
|
outcomeReason: !consensus ? `Rejected: only ${passCount}/3 judges passed` : !passedRegression ? `Rejected: regression ${(regressionResult.passRate * 100).toFixed(0)}% < ${(config.quality.regressionPassRate * 100).toFixed(0)}% threshold` : `Accepted: ${passCount}/3 judges + ${(regressionResult.passRate * 100).toFixed(0)}% regression`,
|
|
10590
10912
|
relatedProposals: proposalOutput.relatedIterations
|
|
10591
10913
|
};
|
|
10914
|
+
const artifactCreatedAt = new Date().toISOString();
|
|
10915
|
+
artifacts.push({
|
|
10916
|
+
id: `artifact_${proposalId}`,
|
|
10917
|
+
createdAt: artifactCreatedAt,
|
|
10918
|
+
artifactType: "evolution",
|
|
10919
|
+
provenance: "native-evolution",
|
|
10920
|
+
sourceId: proposalId,
|
|
10921
|
+
iterationId,
|
|
10922
|
+
proposalId,
|
|
10923
|
+
title: `${skillSlug} · ${proposalOutput.action}`,
|
|
10924
|
+
summary: proposalOutput.diff,
|
|
10925
|
+
targetSkill: skillSlug,
|
|
10926
|
+
operation: proposalOutput.action,
|
|
10927
|
+
outcome: proposal.outcome,
|
|
10928
|
+
clusterType: cluster.type,
|
|
10929
|
+
trigger: "manual",
|
|
10930
|
+
judgeScores: {
|
|
10931
|
+
taskCompletion: judge1.score,
|
|
10932
|
+
correctionAlignment: judge2.score,
|
|
10933
|
+
sideEffectCheck: judge3.score
|
|
10934
|
+
},
|
|
10935
|
+
regression: regressionResult,
|
|
10936
|
+
metrics: {
|
|
10937
|
+
averageJudgeScore: avgScore,
|
|
10938
|
+
taskCompletion: judge1.score,
|
|
10939
|
+
correctionAlignment: judge2.score,
|
|
10940
|
+
sideEffectCheck: judge3.score,
|
|
10941
|
+
regressionPassRate: regressionResult.passRate
|
|
10942
|
+
}
|
|
10943
|
+
});
|
|
10592
10944
|
if (finalAccepted && !dryRun) {
|
|
10593
10945
|
const { meta, content } = parseSkillMd(proposalOutput.proposedSkillMd);
|
|
10594
10946
|
const skillSlug2 = proposalOutput.targetSkill ?? proposal.targetSkill;
|
|
10595
|
-
const skillDir =
|
|
10947
|
+
const skillDir = join8(getGeneralSkillsPath(), skillSlug2);
|
|
10596
10948
|
meta.generation = generation;
|
|
10597
10949
|
meta.score = avgScore;
|
|
10598
10950
|
meta.lastEvolved = new Date().toISOString();
|
|
@@ -10639,15 +10991,21 @@ async function evolveCommand(options) {
|
|
|
10639
10991
|
proposals.push(proposal);
|
|
10640
10992
|
proposalCount++;
|
|
10641
10993
|
}
|
|
10994
|
+
const iterationTimestamp = new Date().toISOString();
|
|
10642
10995
|
const iteration = {
|
|
10643
|
-
id:
|
|
10644
|
-
timestamp:
|
|
10996
|
+
id: iterationId,
|
|
10997
|
+
timestamp: iterationTimestamp,
|
|
10645
10998
|
trigger: "manual",
|
|
10646
10999
|
failureCount: batch.length,
|
|
10647
11000
|
failureClusters,
|
|
10648
11001
|
proposals
|
|
10649
11002
|
};
|
|
10650
11003
|
addIteration(iteration);
|
|
11004
|
+
if (!dryRun) {
|
|
11005
|
+
for (const artifact of artifacts) {
|
|
11006
|
+
appendEvolutionArtifact(artifact);
|
|
11007
|
+
}
|
|
11008
|
+
}
|
|
10651
11009
|
if (hasGraph) {
|
|
10652
11010
|
const accepted2 = proposals.filter((p) => p.outcome === "accepted");
|
|
10653
11011
|
if (accepted2.length > 0) {
|
|
@@ -10705,9 +11063,9 @@ init_skills();
|
|
|
10705
11063
|
// src/core/knowledge-buffer.ts
|
|
10706
11064
|
init_config();
|
|
10707
11065
|
import { readFileSync as readFileSync6, writeFileSync as writeFileSync5, existsSync as existsSync7 } from "node:fs";
|
|
10708
|
-
import { join as
|
|
10709
|
-
var BUFFER_PATH = () =>
|
|
10710
|
-
var DRAFTS_DIR = () =>
|
|
11066
|
+
import { join as join9 } from "node:path";
|
|
11067
|
+
var BUFFER_PATH = () => join9(getHelixDir(), "knowledge-buffer.json");
|
|
11068
|
+
var DRAFTS_DIR = () => join9(getHelixDir(), "drafts");
|
|
10711
11069
|
var MAX_DISCOVERIES = 50;
|
|
10712
11070
|
var MAX_DRAFTS = 10;
|
|
10713
11071
|
var DECAY_RATE = 0.1;
|
|
@@ -10764,9 +11122,9 @@ function saveDraft(draft) {
|
|
|
10764
11122
|
existing.avgScore = draft.avgScore;
|
|
10765
11123
|
existing.iteration++;
|
|
10766
11124
|
existing.lastIterated = new Date().toISOString();
|
|
10767
|
-
const draftDir =
|
|
11125
|
+
const draftDir = join9(DRAFTS_DIR(), draft.skillName);
|
|
10768
11126
|
ensureDir(draftDir);
|
|
10769
|
-
writeFileSync5(
|
|
11127
|
+
writeFileSync5(join9(draftDir, "SKILL.md"), draft.skillMd);
|
|
10770
11128
|
}
|
|
10771
11129
|
} else {
|
|
10772
11130
|
buffer.drafts.push({
|
|
@@ -10780,9 +11138,9 @@ function saveDraft(draft) {
|
|
|
10780
11138
|
iteration: 1,
|
|
10781
11139
|
lastIterated: new Date().toISOString()
|
|
10782
11140
|
});
|
|
10783
|
-
const draftDir =
|
|
11141
|
+
const draftDir = join9(DRAFTS_DIR(), draft.skillName);
|
|
10784
11142
|
ensureDir(draftDir);
|
|
10785
|
-
writeFileSync5(
|
|
11143
|
+
writeFileSync5(join9(draftDir, "SKILL.md"), draft.skillMd);
|
|
10786
11144
|
}
|
|
10787
11145
|
trimAndSave(buffer);
|
|
10788
11146
|
}
|
|
@@ -10882,7 +11240,7 @@ async function statusCommand() {
|
|
|
10882
11240
|
init_data();
|
|
10883
11241
|
init_skills();
|
|
10884
11242
|
import { writeFileSync as writeFileSync6 } from "node:fs";
|
|
10885
|
-
import { join as
|
|
11243
|
+
import { join as join10 } from "node:path";
|
|
10886
11244
|
init_config();
|
|
10887
11245
|
async function reportCommand(options) {
|
|
10888
11246
|
const days = parseInt(options.days ?? "1");
|
|
@@ -10966,8 +11324,8 @@ async function reportCommand(options) {
|
|
|
10966
11324
|
report += `- **${s.slug}**${evolved}
|
|
10967
11325
|
`;
|
|
10968
11326
|
}
|
|
10969
|
-
const outputPath = options.output ??
|
|
10970
|
-
ensureDir(
|
|
11327
|
+
const outputPath = options.output ?? join10(getHelixDir(), "reports", `${date}.md`);
|
|
11328
|
+
ensureDir(join10(getHelixDir(), "reports"));
|
|
10971
11329
|
writeFileSync6(outputPath, report);
|
|
10972
11330
|
console.log(report);
|
|
10973
11331
|
console.log(`
|
|
@@ -10978,7 +11336,7 @@ async function reportCommand(options) {
|
|
|
10978
11336
|
init_config();
|
|
10979
11337
|
init_skills();
|
|
10980
11338
|
init_llm();
|
|
10981
|
-
import { join as
|
|
11339
|
+
import { join as join11 } from "node:path";
|
|
10982
11340
|
async function generalizeCommand(options) {
|
|
10983
11341
|
const verbose = options.verbose ?? false;
|
|
10984
11342
|
const dryRun = options.dryRun ?? false;
|
|
@@ -11041,7 +11399,7 @@ async function generalizeCommand(options) {
|
|
|
11041
11399
|
meta.generation = 1;
|
|
11042
11400
|
meta.score = candidate.confidence;
|
|
11043
11401
|
meta.lastEvolved = new Date().toISOString();
|
|
11044
|
-
const skillDir =
|
|
11402
|
+
const skillDir = join11(getGeneralSkillsPath(), candidate.suggestedName);
|
|
11045
11403
|
writeSkill(skillDir, meta, content);
|
|
11046
11404
|
console.log(` ✓ Created: ${candidate.suggestedName} (${candidate.suggestedLayer} layer)
|
|
11047
11405
|
`);
|
|
@@ -11149,7 +11507,7 @@ Return JSON:
|
|
|
11149
11507
|
init_data();
|
|
11150
11508
|
init_skills();
|
|
11151
11509
|
init_llm();
|
|
11152
|
-
import { join as
|
|
11510
|
+
import { join as join12 } from "node:path";
|
|
11153
11511
|
async function specializeCommand(options) {
|
|
11154
11512
|
const verbose = options.verbose ?? false;
|
|
11155
11513
|
const dryRun = options.dryRun ?? false;
|
|
@@ -11220,8 +11578,8 @@ async function specializeCommand(options) {
|
|
|
11220
11578
|
meta.generation = 1;
|
|
11221
11579
|
meta.score = candidate.confidence;
|
|
11222
11580
|
meta.lastEvolved = new Date().toISOString();
|
|
11223
|
-
const projectSkillsDir =
|
|
11224
|
-
const skillDir =
|
|
11581
|
+
const projectSkillsDir = join12(process.cwd(), ".helix", "skills");
|
|
11582
|
+
const skillDir = join12(projectSkillsDir, candidate.suggestedName);
|
|
11225
11583
|
writeSkill(skillDir, meta, content);
|
|
11226
11584
|
console.log(` ✓ Created: ${candidate.suggestedName} (project layer, parent: ${candidate.domainSkill})
|
|
11227
11585
|
`);
|
|
@@ -11318,10 +11676,11 @@ Return JSON:
|
|
|
11318
11676
|
// src/commands/graph.ts
|
|
11319
11677
|
import { writeFileSync as writeFileSync8 } from "node:fs";
|
|
11320
11678
|
import { execSync } from "node:child_process";
|
|
11321
|
-
import { join as
|
|
11679
|
+
import { join as join14 } from "node:path";
|
|
11322
11680
|
import { tmpdir } from "node:os";
|
|
11323
11681
|
|
|
11324
11682
|
// src/core/network.ts
|
|
11683
|
+
init_ontology();
|
|
11325
11684
|
init_skills();
|
|
11326
11685
|
init_data();
|
|
11327
11686
|
init_config();
|
|
@@ -11371,7 +11730,12 @@ async function fullRebuild(verbose) {
|
|
|
11371
11730
|
status: "active",
|
|
11372
11731
|
tags: s.meta.tags ?? [],
|
|
11373
11732
|
failureCount: s.meta.failureCount ?? 0,
|
|
11374
|
-
lastEvolved: s.meta.lastEvolved ?? ""
|
|
11733
|
+
lastEvolved: s.meta.lastEvolved ?? "",
|
|
11734
|
+
cognitiveRole: s.meta.cognitiveRole,
|
|
11735
|
+
stabilityState: s.meta.stabilityState,
|
|
11736
|
+
plasticityState: s.meta.plasticityState,
|
|
11737
|
+
capabilities: s.meta.capabilities,
|
|
11738
|
+
lineageId: s.meta.lineageId
|
|
11375
11739
|
}));
|
|
11376
11740
|
const edges = [];
|
|
11377
11741
|
for (const s of skills) {
|
|
@@ -11399,6 +11763,7 @@ async function fullRebuild(verbose) {
|
|
|
11399
11763
|
const clusters = clusterSkills(nodes, edges);
|
|
11400
11764
|
const graph = {
|
|
11401
11765
|
updated: new Date().toISOString(),
|
|
11766
|
+
ontologyVersion: ONTOLOGY_SPEC_VERSION,
|
|
11402
11767
|
nodes,
|
|
11403
11768
|
edges: deduplicateEdges(edges),
|
|
11404
11769
|
clusters
|
|
@@ -11671,29 +12036,29 @@ function detectMergeCandidates(enhances, coEvolves, skills) {
|
|
|
11671
12036
|
init_data();
|
|
11672
12037
|
init_skills();
|
|
11673
12038
|
import { writeFileSync as writeFileSync7, mkdirSync as mkdirSync3 } from "node:fs";
|
|
11674
|
-
import { join as
|
|
12039
|
+
import { join as join13 } from "node:path";
|
|
11675
12040
|
function syncToObsidian(vaultPath, verbose = false) {
|
|
11676
12041
|
const graph = loadSkillGraph();
|
|
11677
12042
|
const skills = loadAllGeneralSkills();
|
|
11678
|
-
const skillsDir =
|
|
11679
|
-
const reportsDir =
|
|
12043
|
+
const skillsDir = join13(vaultPath, "Skills");
|
|
12044
|
+
const reportsDir = join13(vaultPath, "Reports");
|
|
11680
12045
|
mkdirSync3(skillsDir, { recursive: true });
|
|
11681
12046
|
mkdirSync3(reportsDir, { recursive: true });
|
|
11682
12047
|
for (const node of graph.nodes) {
|
|
11683
12048
|
const skill = skills.find((s) => s.slug === node.id);
|
|
11684
12049
|
const note = generateSkillNote(node, graph.edges, skill ?? undefined);
|
|
11685
|
-
const notePath =
|
|
12050
|
+
const notePath = join13(skillsDir, `${node.id}.md`);
|
|
11686
12051
|
writeFileSync7(notePath, note);
|
|
11687
12052
|
if (verbose)
|
|
11688
12053
|
console.log(` ✓ ${node.id}.md`);
|
|
11689
12054
|
}
|
|
11690
12055
|
const indexNote = generateIndexNote(graph);
|
|
11691
|
-
writeFileSync7(
|
|
12056
|
+
writeFileSync7(join13(vaultPath, "HelixEvo Index.md"), indexNote);
|
|
11692
12057
|
const recent = getRecentIterations(7);
|
|
11693
12058
|
if (recent.length > 0) {
|
|
11694
12059
|
const report = generateEvolutionReport(recent);
|
|
11695
12060
|
const date = new Date().toISOString().slice(0, 10);
|
|
11696
|
-
writeFileSync7(
|
|
12061
|
+
writeFileSync7(join13(reportsDir, `Evolution ${date}.md`), report);
|
|
11697
12062
|
}
|
|
11698
12063
|
console.log(` ✓ Synced ${graph.nodes.length} skills to ${vaultPath}`);
|
|
11699
12064
|
}
|
|
@@ -12052,7 +12417,7 @@ ${mermaidCode}
|
|
|
12052
12417
|
});
|
|
12053
12418
|
</script>
|
|
12054
12419
|
</body></html>`;
|
|
12055
|
-
const htmlPath =
|
|
12420
|
+
const htmlPath = join14(tmpdir(), "helix-network.html");
|
|
12056
12421
|
writeFileSync8(htmlPath, html);
|
|
12057
12422
|
execSync(`open "${htmlPath}"`);
|
|
12058
12423
|
console.log(` ✓ Opened in browser`);
|
|
@@ -12117,7 +12482,7 @@ function renderScoreBar(score) {
|
|
|
12117
12482
|
init_config();
|
|
12118
12483
|
init_skills();
|
|
12119
12484
|
init_llm();
|
|
12120
|
-
import { join as
|
|
12485
|
+
import { join as join15 } from "node:path";
|
|
12121
12486
|
import { readFileSync as readFileSync7, existsSync as existsSync9 } from "node:fs";
|
|
12122
12487
|
async function researchCommand(options) {
|
|
12123
12488
|
const verbose = options.verbose ?? false;
|
|
@@ -12233,7 +12598,7 @@ Only include discoveries that are NOT already covered by current skills.`
|
|
|
12233
12598
|
meta.score = result.avgScore / 10;
|
|
12234
12599
|
meta.lastEvolved = new Date().toISOString();
|
|
12235
12600
|
meta.tags = [...meta.tags ?? [], "research-discovered"];
|
|
12236
|
-
const skillDir =
|
|
12601
|
+
const skillDir = join15(getGeneralSkillsPath(), hypothesis.skillName);
|
|
12237
12602
|
writeSkill(skillDir, meta, content);
|
|
12238
12603
|
console.log(` ✓ Created: ${hypothesis.skillName} (from research)
|
|
12239
12604
|
`);
|
|
@@ -12281,7 +12646,7 @@ async function understandGoals(projectPath, skills) {
|
|
|
12281
12646
|
const paths = projectPath ? [projectPath] : [process.cwd()];
|
|
12282
12647
|
for (const p of paths) {
|
|
12283
12648
|
for (const file of ["README.md", "CLAUDE.md", "package.json", ".agents/AGENTS.md"]) {
|
|
12284
|
-
const fullPath =
|
|
12649
|
+
const fullPath = join15(p, file);
|
|
12285
12650
|
if (existsSync9(fullPath)) {
|
|
12286
12651
|
const content = readFileSync7(fullPath, "utf-8").slice(0, 2000);
|
|
12287
12652
|
context.push(`## ${file}
|
|
@@ -12443,15 +12808,126 @@ ${replay.slice(0, 800)}`
|
|
|
12443
12808
|
|
|
12444
12809
|
// src/commands/dashboard.ts
|
|
12445
12810
|
import { execSync as execSync2, spawn as spawn2 } from "node:child_process";
|
|
12446
|
-
import { join as
|
|
12447
|
-
import { existsSync as
|
|
12811
|
+
import { join as join17, dirname as dirname3 } from "node:path";
|
|
12812
|
+
import { existsSync as existsSync11, cpSync as cpSync3, mkdirSync as mkdirSync5, readdirSync as readdirSync3, readFileSync as readFileSync9, rmSync as rmSync2, writeFileSync as writeFileSync10 } from "node:fs";
|
|
12448
12813
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
12449
|
-
import { homedir as
|
|
12814
|
+
import { homedir as homedir4 } from "node:os";
|
|
12450
12815
|
init_skills();
|
|
12451
12816
|
init_data();
|
|
12817
|
+
|
|
12818
|
+
// src/utils/update-check.ts
|
|
12819
|
+
import { readFileSync as readFileSync8, writeFileSync as writeFileSync9, existsSync as existsSync10, mkdirSync as mkdirSync4 } from "node:fs";
|
|
12820
|
+
import { join as join16 } from "node:path";
|
|
12821
|
+
import { homedir as homedir3 } from "node:os";
|
|
12822
|
+
var HELIX_DIR2 = join16(homedir3(), ".helix");
|
|
12823
|
+
var CACHE_PATH = join16(HELIX_DIR2, "update-check.json");
|
|
12824
|
+
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;
|
|
12825
|
+
var REGISTRY_URL = "https://registry.npmjs.org/helixevo/latest";
|
|
12826
|
+
function readCache() {
|
|
12827
|
+
try {
|
|
12828
|
+
if (!existsSync10(CACHE_PATH))
|
|
12829
|
+
return null;
|
|
12830
|
+
return JSON.parse(readFileSync8(CACHE_PATH, "utf-8"));
|
|
12831
|
+
} catch {
|
|
12832
|
+
return null;
|
|
12833
|
+
}
|
|
12834
|
+
}
|
|
12835
|
+
function writeCache(cache) {
|
|
12836
|
+
try {
|
|
12837
|
+
if (!existsSync10(HELIX_DIR2))
|
|
12838
|
+
mkdirSync4(HELIX_DIR2, { recursive: true });
|
|
12839
|
+
writeFileSync9(CACHE_PATH, JSON.stringify(cache));
|
|
12840
|
+
} catch {}
|
|
12841
|
+
}
|
|
12842
|
+
function hasNewerVersion(current, latest) {
|
|
12843
|
+
const c = current.split(".").map(Number);
|
|
12844
|
+
const l = latest.split(".").map(Number);
|
|
12845
|
+
for (let i = 0;i < 3; i++) {
|
|
12846
|
+
if ((l[i] ?? 0) > (c[i] ?? 0))
|
|
12847
|
+
return true;
|
|
12848
|
+
if ((l[i] ?? 0) < (c[i] ?? 0))
|
|
12849
|
+
return false;
|
|
12850
|
+
}
|
|
12851
|
+
return false;
|
|
12852
|
+
}
|
|
12853
|
+
async function fetchLatestVersion() {
|
|
12854
|
+
try {
|
|
12855
|
+
const controller = new AbortController;
|
|
12856
|
+
const timeout = setTimeout(() => controller.abort(), 3000);
|
|
12857
|
+
const res = await fetch(REGISTRY_URL, { signal: controller.signal });
|
|
12858
|
+
clearTimeout(timeout);
|
|
12859
|
+
if (!res.ok)
|
|
12860
|
+
return null;
|
|
12861
|
+
const data = await res.json();
|
|
12862
|
+
return data.version ?? null;
|
|
12863
|
+
} catch {
|
|
12864
|
+
return null;
|
|
12865
|
+
}
|
|
12866
|
+
}
|
|
12867
|
+
async function getUpdateInfo(currentVersion = VERSION, forceRefresh = false) {
|
|
12868
|
+
const cache = forceRefresh ? null : readCache();
|
|
12869
|
+
if (cache && Date.now() - cache.lastCheck < CHECK_INTERVAL_MS) {
|
|
12870
|
+
return {
|
|
12871
|
+
currentVersion,
|
|
12872
|
+
latestVersion: cache.latestVersion,
|
|
12873
|
+
hasUpdate: hasNewerVersion(currentVersion, cache.latestVersion),
|
|
12874
|
+
source: "cache"
|
|
12875
|
+
};
|
|
12876
|
+
}
|
|
12877
|
+
const latest = await fetchLatestVersion();
|
|
12878
|
+
if (!latest) {
|
|
12879
|
+
return {
|
|
12880
|
+
currentVersion,
|
|
12881
|
+
latestVersion: cache?.latestVersion ?? null,
|
|
12882
|
+
hasUpdate: cache ? hasNewerVersion(currentVersion, cache.latestVersion) : false,
|
|
12883
|
+
source: cache ? "cache" : "none"
|
|
12884
|
+
};
|
|
12885
|
+
}
|
|
12886
|
+
writeCache({ lastCheck: Date.now(), latestVersion: latest });
|
|
12887
|
+
return {
|
|
12888
|
+
currentVersion,
|
|
12889
|
+
latestVersion: latest,
|
|
12890
|
+
hasUpdate: hasNewerVersion(currentVersion, latest),
|
|
12891
|
+
source: "network"
|
|
12892
|
+
};
|
|
12893
|
+
}
|
|
12894
|
+
async function checkForUpdates() {
|
|
12895
|
+
try {
|
|
12896
|
+
const update = await getUpdateInfo(VERSION);
|
|
12897
|
+
if (update.hasUpdate && update.latestVersion) {
|
|
12898
|
+
printUpdateBanner(update.currentVersion, update.latestVersion);
|
|
12899
|
+
}
|
|
12900
|
+
} catch {}
|
|
12901
|
+
}
|
|
12902
|
+
function printUpdateBanner(currentVersion, latestVersion) {
|
|
12903
|
+
const yellow = "\x1B[33m";
|
|
12904
|
+
const green = "\x1B[32m";
|
|
12905
|
+
const cyan = "\x1B[36m";
|
|
12906
|
+
const bold = "\x1B[1m";
|
|
12907
|
+
const dim = "\x1B[2m";
|
|
12908
|
+
const reset = "\x1B[0m";
|
|
12909
|
+
console.log();
|
|
12910
|
+
console.log(`${yellow} ╭──────────────────────────────────────────────╮${reset}`);
|
|
12911
|
+
console.log(`${yellow} │ │${reset}`);
|
|
12912
|
+
console.log(`${yellow} │ ${bold}Update available!${reset}${yellow} ${dim}v${currentVersion}${reset}${yellow} → ${green}${bold}v${latestVersion}${reset}${yellow} │${reset}`);
|
|
12913
|
+
console.log(`${yellow} │ │${reset}`);
|
|
12914
|
+
console.log(`${yellow} │ ${reset}Run ${cyan}npm install -g helixevo@latest${reset}${yellow} │${reset}`);
|
|
12915
|
+
console.log(`${yellow} │ ${reset}to update${yellow} │${reset}`);
|
|
12916
|
+
console.log(`${yellow} │ │${reset}`);
|
|
12917
|
+
console.log(`${yellow} ╰──────────────────────────────────────────────╯${reset}`);
|
|
12918
|
+
console.log();
|
|
12919
|
+
}
|
|
12920
|
+
|
|
12921
|
+
// src/commands/dashboard.ts
|
|
12452
12922
|
var __filename = "/Users/tianchichen/Documents/GitHub/helixevo/src/commands/dashboard.ts";
|
|
12453
|
-
var HELIX_DASHBOARD_DIR =
|
|
12923
|
+
var HELIX_DASHBOARD_DIR = join17(homedir4(), ".helix", "dashboard");
|
|
12924
|
+
var DASHBOARD_SKIP_AUTO_UPDATE_ENV = "HELIXEVO_DASHBOARD_SKIP_AUTO_UPDATE";
|
|
12454
12925
|
async function dashboardCommand(options) {
|
|
12926
|
+
if (options.autoUpdate !== false && process.env[DASHBOARD_SKIP_AUTO_UPDATE_ENV] !== "1" && !findDevDashboard()) {
|
|
12927
|
+
const didRelaunch = await maybeAutoUpdateAndRelaunch(options);
|
|
12928
|
+
if (didRelaunch)
|
|
12929
|
+
return;
|
|
12930
|
+
}
|
|
12455
12931
|
const dir = prepareDashboard();
|
|
12456
12932
|
if (!dir) {
|
|
12457
12933
|
console.error(` Dashboard not found.
|
|
@@ -12461,7 +12937,7 @@ async function dashboardCommand(options) {
|
|
|
12461
12937
|
console.error(" cd helixevo/dashboard && npm install && npx next dev --port 3847");
|
|
12462
12938
|
process.exit(1);
|
|
12463
12939
|
}
|
|
12464
|
-
if (!
|
|
12940
|
+
if (!existsSync11(join17(dir, "node_modules"))) {
|
|
12465
12941
|
console.log(" Installing dashboard dependencies...");
|
|
12466
12942
|
try {
|
|
12467
12943
|
execSync2("npm install --no-audit --no-fund", { cwd: dir, stdio: "inherit" });
|
|
@@ -12474,22 +12950,22 @@ async function dashboardCommand(options) {
|
|
|
12474
12950
|
}
|
|
12475
12951
|
ensureSkillGraph();
|
|
12476
12952
|
if (options.background) {
|
|
12477
|
-
const logFile =
|
|
12953
|
+
const logFile = join17(homedir4(), ".helix", "dashboard.log");
|
|
12478
12954
|
const out = __require("fs").openSync(logFile, "a");
|
|
12479
12955
|
const err = __require("fs").openSync(logFile, "a");
|
|
12480
|
-
let
|
|
12956
|
+
let currentVersion2 = VERSION;
|
|
12481
12957
|
try {
|
|
12482
|
-
|
|
12958
|
+
currentVersion2 = execSync2("helixevo --version 2>/dev/null", { encoding: "utf-8" }).trim() || VERSION;
|
|
12483
12959
|
} catch {}
|
|
12484
12960
|
const child = spawn2("npx", ["next", "dev", "--port", "3847"], {
|
|
12485
12961
|
cwd: dir,
|
|
12486
12962
|
stdio: ["ignore", out, err],
|
|
12487
|
-
env: { ...process.env, HELIXEVO_VERSION:
|
|
12963
|
+
env: { ...process.env, HELIXEVO_VERSION: currentVersion2 },
|
|
12488
12964
|
detached: true
|
|
12489
12965
|
});
|
|
12490
12966
|
child.unref();
|
|
12491
|
-
|
|
12492
|
-
console.log(` \uD83C\uDF10 HelixEvo Dashboard v${
|
|
12967
|
+
writeFileSync10(join17(homedir4(), ".helix", "dashboard.pid"), String(child.pid));
|
|
12968
|
+
console.log(` \uD83C\uDF10 HelixEvo Dashboard v${currentVersion2} running in background`);
|
|
12493
12969
|
console.log(` http://localhost:3847`);
|
|
12494
12970
|
console.log(` Logs: ${logFile}`);
|
|
12495
12971
|
console.log(` Stop: helixevo dashboard --stop
|
|
@@ -12503,10 +12979,54 @@ async function dashboardCommand(options) {
|
|
|
12503
12979
|
}, 2000);
|
|
12504
12980
|
process.exit(0);
|
|
12505
12981
|
}
|
|
12506
|
-
|
|
12982
|
+
let currentVersion = VERSION;
|
|
12983
|
+
try {
|
|
12984
|
+
currentVersion = execSync2("helixevo --version 2>/dev/null", { encoding: "utf-8" }).trim() || VERSION;
|
|
12985
|
+
} catch {}
|
|
12986
|
+
console.log(` \uD83C\uDF10 Starting HelixEvo Dashboard v${currentVersion} at http://localhost:3847
|
|
12507
12987
|
`);
|
|
12508
12988
|
launchDashboard(dir, true);
|
|
12509
12989
|
}
|
|
12990
|
+
async function maybeAutoUpdateAndRelaunch(options) {
|
|
12991
|
+
const update = await getUpdateInfo(VERSION);
|
|
12992
|
+
if (!update.hasUpdate || !update.latestVersion)
|
|
12993
|
+
return false;
|
|
12994
|
+
console.log(` ⟳ New HelixEvo version detected: v${VERSION} → v${update.latestVersion}`);
|
|
12995
|
+
console.log(` Updating before launching dashboard...
|
|
12996
|
+
`);
|
|
12997
|
+
try {
|
|
12998
|
+
execSync2("npm install -g helixevo@latest", {
|
|
12999
|
+
stdio: "inherit",
|
|
13000
|
+
timeout: 120000,
|
|
13001
|
+
env: { ...process.env }
|
|
13002
|
+
});
|
|
13003
|
+
} catch {
|
|
13004
|
+
console.warn(`
|
|
13005
|
+
Auto-update failed. Continuing with the current installed version.
|
|
13006
|
+
`);
|
|
13007
|
+
return false;
|
|
13008
|
+
}
|
|
13009
|
+
console.log(`
|
|
13010
|
+
✓ Updated to v${update.latestVersion}. Relaunching dashboard...
|
|
13011
|
+
`);
|
|
13012
|
+
const executable = process.platform === "win32" ? "helixevo.cmd" : "helixevo";
|
|
13013
|
+
const args = ["dashboard"];
|
|
13014
|
+
if (options.background)
|
|
13015
|
+
args.push("--background");
|
|
13016
|
+
if (options.autoUpdate === false)
|
|
13017
|
+
args.push("--no-auto-update");
|
|
13018
|
+
await new Promise((resolve, reject) => {
|
|
13019
|
+
const child = spawn2(executable, args, {
|
|
13020
|
+
stdio: "inherit",
|
|
13021
|
+
env: { ...process.env, [DASHBOARD_SKIP_AUTO_UPDATE_ENV]: "1" }
|
|
13022
|
+
});
|
|
13023
|
+
child.on("error", reject);
|
|
13024
|
+
child.on("close", (code) => {
|
|
13025
|
+
process.exit(code ?? 0);
|
|
13026
|
+
});
|
|
13027
|
+
});
|
|
13028
|
+
return true;
|
|
13029
|
+
}
|
|
12510
13030
|
var RESTART_EXIT_CODE = 75;
|
|
12511
13031
|
function launchDashboard(dir, openBrowser) {
|
|
12512
13032
|
let currentVersion = VERSION;
|
|
@@ -12533,8 +13053,8 @@ function launchDashboard(dir, openBrowser) {
|
|
|
12533
13053
|
\uD83D\uDD04 Restarting dashboard after update...
|
|
12534
13054
|
`);
|
|
12535
13055
|
setTimeout(() => {
|
|
12536
|
-
const nextCache =
|
|
12537
|
-
if (
|
|
13056
|
+
const nextCache = join17(dir, ".next");
|
|
13057
|
+
if (existsSync11(nextCache)) {
|
|
12538
13058
|
try {
|
|
12539
13059
|
rmSync2(nextCache, { recursive: true });
|
|
12540
13060
|
} catch {}
|
|
@@ -12560,20 +13080,20 @@ function prepareDashboard() {
|
|
|
12560
13080
|
const npmSource = findNpmDashboard();
|
|
12561
13081
|
if (npmSource)
|
|
12562
13082
|
return copyToHelix(npmSource);
|
|
12563
|
-
if (
|
|
13083
|
+
if (existsSync11(join17(HELIX_DASHBOARD_DIR, "package.json"))) {
|
|
12564
13084
|
return HELIX_DASHBOARD_DIR;
|
|
12565
13085
|
}
|
|
12566
13086
|
return null;
|
|
12567
13087
|
}
|
|
12568
13088
|
function findDevDashboard() {
|
|
12569
13089
|
const candidates = [
|
|
12570
|
-
|
|
13090
|
+
join17(process.cwd(), "dashboard")
|
|
12571
13091
|
];
|
|
12572
13092
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
12573
|
-
candidates.push(
|
|
12574
|
-
candidates.push(
|
|
13093
|
+
candidates.push(join17(home, "Documents", "GitHub", "helixevo", "dashboard"));
|
|
13094
|
+
candidates.push(join17(home, "Documents", "GitHub", "skillgraph", "dashboard"));
|
|
12575
13095
|
for (const dir of candidates) {
|
|
12576
|
-
if (
|
|
13096
|
+
if (existsSync11(join17(dir, "package.json")) && !dir.includes("node_modules")) {
|
|
12577
13097
|
return dir;
|
|
12578
13098
|
}
|
|
12579
13099
|
}
|
|
@@ -12584,15 +13104,15 @@ function findNpmDashboard() {
|
|
|
12584
13104
|
try {
|
|
12585
13105
|
const thisFile = typeof __filename !== "undefined" ? __filename : fileURLToPath2(import.meta.url);
|
|
12586
13106
|
const pkgRoot = dirname3(dirname3(thisFile));
|
|
12587
|
-
candidates.push(
|
|
13107
|
+
candidates.push(join17(pkgRoot, "dashboard"));
|
|
12588
13108
|
} catch {}
|
|
12589
13109
|
try {
|
|
12590
13110
|
const globalPrefix = execSync2("npm prefix -g", { encoding: "utf-8" }).trim();
|
|
12591
|
-
candidates.push(
|
|
12592
|
-
candidates.push(
|
|
13111
|
+
candidates.push(join17(globalPrefix, "lib", "node_modules", "helixevo", "dashboard"));
|
|
13112
|
+
candidates.push(join17(globalPrefix, "node_modules", "helixevo", "dashboard"));
|
|
12593
13113
|
} catch {}
|
|
12594
13114
|
for (const dir of candidates) {
|
|
12595
|
-
if (
|
|
13115
|
+
if (existsSync11(join17(dir, "package.json"))) {
|
|
12596
13116
|
return dir;
|
|
12597
13117
|
}
|
|
12598
13118
|
}
|
|
@@ -12600,10 +13120,10 @@ function findNpmDashboard() {
|
|
|
12600
13120
|
}
|
|
12601
13121
|
function getInstalledDashboardVersion() {
|
|
12602
13122
|
try {
|
|
12603
|
-
const versionFile =
|
|
12604
|
-
if (!
|
|
13123
|
+
const versionFile = join17(HELIX_DASHBOARD_DIR, ".helixevo-version");
|
|
13124
|
+
if (!existsSync11(versionFile))
|
|
12605
13125
|
return null;
|
|
12606
|
-
return
|
|
13126
|
+
return readFileSync9(versionFile, "utf-8").trim();
|
|
12607
13127
|
} catch {
|
|
12608
13128
|
return null;
|
|
12609
13129
|
}
|
|
@@ -12611,8 +13131,8 @@ function getInstalledDashboardVersion() {
|
|
|
12611
13131
|
function copyToHelix(sourceDir) {
|
|
12612
13132
|
let sourceVersion = VERSION;
|
|
12613
13133
|
try {
|
|
12614
|
-
const srcRoot =
|
|
12615
|
-
const pkg2 = JSON.parse(
|
|
13134
|
+
const srcRoot = join17(sourceDir, "..", "package.json");
|
|
13135
|
+
const pkg2 = JSON.parse(readFileSync9(srcRoot, "utf-8"));
|
|
12616
13136
|
if (pkg2.name === "helixevo" && pkg2.version)
|
|
12617
13137
|
sourceVersion = pkg2.version;
|
|
12618
13138
|
} catch {}
|
|
@@ -12625,37 +13145,37 @@ function copyToHelix(sourceDir) {
|
|
|
12625
13145
|
} else {
|
|
12626
13146
|
console.log(" Setting up dashboard at ~/.helix/dashboard...");
|
|
12627
13147
|
}
|
|
12628
|
-
|
|
13148
|
+
mkdirSync5(HELIX_DASHBOARD_DIR, { recursive: true });
|
|
12629
13149
|
let depsChanged = true;
|
|
12630
13150
|
try {
|
|
12631
|
-
const srcDeps =
|
|
12632
|
-
const dstDeps =
|
|
13151
|
+
const srcDeps = readFileSync9(join17(sourceDir, "package.json"), "utf-8");
|
|
13152
|
+
const dstDeps = readFileSync9(join17(HELIX_DASHBOARD_DIR, "package.json"), "utf-8");
|
|
12633
13153
|
const srcPkg = JSON.parse(srcDeps);
|
|
12634
13154
|
const dstPkg = JSON.parse(dstDeps);
|
|
12635
13155
|
depsChanged = JSON.stringify(srcPkg.dependencies) !== JSON.stringify(dstPkg.dependencies) || JSON.stringify(srcPkg.devDependencies) !== JSON.stringify(dstPkg.devDependencies);
|
|
12636
13156
|
} catch {
|
|
12637
13157
|
depsChanged = true;
|
|
12638
13158
|
}
|
|
12639
|
-
const items =
|
|
13159
|
+
const items = readdirSync3(sourceDir, { withFileTypes: true });
|
|
12640
13160
|
for (const item of items) {
|
|
12641
13161
|
if (item.name === "node_modules" || item.name === ".next" || item.name === "package-lock.json" || item.name === ".env.local")
|
|
12642
13162
|
continue;
|
|
12643
|
-
const src =
|
|
12644
|
-
const dest =
|
|
13163
|
+
const src = join17(sourceDir, item.name);
|
|
13164
|
+
const dest = join17(HELIX_DASHBOARD_DIR, item.name);
|
|
12645
13165
|
cpSync3(src, dest, { recursive: true });
|
|
12646
13166
|
}
|
|
12647
13167
|
if (depsChanged) {
|
|
12648
|
-
const oldModules =
|
|
12649
|
-
if (
|
|
13168
|
+
const oldModules = join17(HELIX_DASHBOARD_DIR, "node_modules");
|
|
13169
|
+
if (existsSync11(oldModules))
|
|
12650
13170
|
rmSync2(oldModules, { recursive: true });
|
|
12651
|
-
const oldLock =
|
|
12652
|
-
if (
|
|
13171
|
+
const oldLock = join17(HELIX_DASHBOARD_DIR, "package-lock.json");
|
|
13172
|
+
if (existsSync11(oldLock))
|
|
12653
13173
|
rmSync2(oldLock);
|
|
12654
13174
|
}
|
|
12655
|
-
const nextCache =
|
|
12656
|
-
if (
|
|
13175
|
+
const nextCache = join17(HELIX_DASHBOARD_DIR, ".next");
|
|
13176
|
+
if (existsSync11(nextCache))
|
|
12657
13177
|
rmSync2(nextCache, { recursive: true });
|
|
12658
|
-
|
|
13178
|
+
writeFileSync10(join17(HELIX_DASHBOARD_DIR, ".helixevo-version"), sourceVersion);
|
|
12659
13179
|
return HELIX_DASHBOARD_DIR;
|
|
12660
13180
|
}
|
|
12661
13181
|
function ensureSkillGraph() {
|
|
@@ -12697,13 +13217,13 @@ function ensureSkillGraph() {
|
|
|
12697
13217
|
}
|
|
12698
13218
|
|
|
12699
13219
|
// src/commands/watch.ts
|
|
12700
|
-
import { join as
|
|
12701
|
-
import { existsSync as
|
|
13220
|
+
import { join as join19 } from "node:path";
|
|
13221
|
+
import { existsSync as existsSync14 } from "node:fs";
|
|
12702
13222
|
|
|
12703
13223
|
// src/core/auto-capture.ts
|
|
12704
13224
|
init_data();
|
|
12705
13225
|
init_llm();
|
|
12706
|
-
import { readFileSync as
|
|
13226
|
+
import { readFileSync as readFileSync10, existsSync as existsSync12, statSync as statSync2 } from "node:fs";
|
|
12707
13227
|
var CORRECTION_SIGNALS = [
|
|
12708
13228
|
/\bno[, ]+(?:that's|thats|that is)\s+(?:wrong|incorrect|not right)/i,
|
|
12709
13229
|
/\bdon'?t\s+do\s+(?:that|it\s+like\s+that)/i,
|
|
@@ -12791,17 +13311,17 @@ If no corrections found, return: { "corrections": [] }`
|
|
|
12791
13311
|
}
|
|
12792
13312
|
function watchEvents(options) {
|
|
12793
13313
|
const { eventsPath, project, onCapture, onError, pollIntervalMs = 5000 } = options;
|
|
12794
|
-
let lastSize =
|
|
13314
|
+
let lastSize = existsSync12(eventsPath) ? statSync2(eventsPath).size : 0;
|
|
12795
13315
|
let messageBuffer = [];
|
|
12796
13316
|
let pendingExtraction = false;
|
|
12797
13317
|
const interval = setInterval(async () => {
|
|
12798
13318
|
try {
|
|
12799
|
-
if (!
|
|
13319
|
+
if (!existsSync12(eventsPath))
|
|
12800
13320
|
return;
|
|
12801
13321
|
const currentSize = statSync2(eventsPath).size;
|
|
12802
13322
|
if (currentSize <= lastSize)
|
|
12803
13323
|
return;
|
|
12804
|
-
const content =
|
|
13324
|
+
const content = readFileSync10(eventsPath, "utf-8");
|
|
12805
13325
|
const lines = content.trim().split(`
|
|
12806
13326
|
`).filter(Boolean);
|
|
12807
13327
|
const newLines = lines.slice(messageBuffer.length);
|
|
@@ -12843,22 +13363,22 @@ init_data();
|
|
|
12843
13363
|
// src/core/metrics.ts
|
|
12844
13364
|
init_config();
|
|
12845
13365
|
init_data();
|
|
12846
|
-
import { readFileSync as
|
|
12847
|
-
import { join as
|
|
13366
|
+
import { readFileSync as readFileSync11, writeFileSync as writeFileSync11, existsSync as existsSync13 } from "node:fs";
|
|
13367
|
+
import { join as join18 } from "node:path";
|
|
12848
13368
|
function getMetricsPath() {
|
|
12849
|
-
return
|
|
13369
|
+
return join18(getHelixDir(), "metrics.json");
|
|
12850
13370
|
}
|
|
12851
13371
|
function loadMetrics() {
|
|
12852
13372
|
const path = getMetricsPath();
|
|
12853
|
-
if (!
|
|
13373
|
+
if (!existsSync13(path)) {
|
|
12854
13374
|
return { updated: new Date().toISOString(), skills: [], globalCorrectionRate: [], evolutionImpact: [] };
|
|
12855
13375
|
}
|
|
12856
|
-
return JSON.parse(
|
|
13376
|
+
return JSON.parse(readFileSync11(path, "utf-8"));
|
|
12857
13377
|
}
|
|
12858
13378
|
function saveMetrics(store) {
|
|
12859
13379
|
ensureDir(getHelixDir());
|
|
12860
13380
|
store.updated = new Date().toISOString();
|
|
12861
|
-
|
|
13381
|
+
writeFileSync11(getMetricsPath(), JSON.stringify(store, null, 2));
|
|
12862
13382
|
}
|
|
12863
13383
|
function updateMetrics() {
|
|
12864
13384
|
const failures = loadFailures();
|
|
@@ -13033,14 +13553,14 @@ async function watchCommand(options) {
|
|
|
13033
13553
|
const verbose = options.verbose ?? false;
|
|
13034
13554
|
const autoEvolve = options.evolve !== false;
|
|
13035
13555
|
const project = options.project ?? null;
|
|
13036
|
-
const eventsPath = options.events ??
|
|
13556
|
+
const eventsPath = options.events ?? join19(process.cwd(), "events.jsonl");
|
|
13037
13557
|
console.log(`\uD83E\uDDEC HelixEvo Watch Mode — Always-On Learning
|
|
13038
13558
|
`);
|
|
13039
13559
|
console.log(` Events: ${eventsPath}`);
|
|
13040
13560
|
console.log(` Project: ${project ?? "(auto-detect)"}`);
|
|
13041
13561
|
console.log(` Auto-evolve: ${autoEvolve ? "ON" : "OFF"}`);
|
|
13042
13562
|
console.log();
|
|
13043
|
-
if (!
|
|
13563
|
+
if (!existsSync14(eventsPath)) {
|
|
13044
13564
|
console.log(` ⚠ Events file not found yet. Will start watching when it appears.`);
|
|
13045
13565
|
console.log(` Expected at: ${eventsPath}
|
|
13046
13566
|
`);
|
|
@@ -13188,10 +13708,12 @@ async function metricsCommand(options) {
|
|
|
13188
13708
|
}
|
|
13189
13709
|
|
|
13190
13710
|
// src/commands/project-setup.ts
|
|
13711
|
+
init_data();
|
|
13191
13712
|
init_skills();
|
|
13192
13713
|
init_llm();
|
|
13193
|
-
import { join as
|
|
13194
|
-
import { existsSync as
|
|
13714
|
+
import { isAbsolute, join as join20, normalize, resolve } from "node:path";
|
|
13715
|
+
import { existsSync as existsSync15, readFileSync as readFileSync12, writeFileSync as writeFileSync12, mkdirSync as mkdirSync6, readdirSync as readdirSync4 } from "node:fs";
|
|
13716
|
+
import { homedir as homedir5 } from "node:os";
|
|
13195
13717
|
|
|
13196
13718
|
// src/prompts/project-analysis.ts
|
|
13197
13719
|
function buildProjectAnalysisPrompt(projectContext, skills) {
|
|
@@ -13255,6 +13777,23 @@ Return JSON:
|
|
|
13255
13777
|
|
|
13256
13778
|
// src/commands/project-setup.ts
|
|
13257
13779
|
init_config();
|
|
13780
|
+
function stripTrailingSeparator(path) {
|
|
13781
|
+
if (path.length <= 1)
|
|
13782
|
+
return path;
|
|
13783
|
+
return path.replace(/[\\/]+$/, "") || path;
|
|
13784
|
+
}
|
|
13785
|
+
function expandHomePath(path) {
|
|
13786
|
+
if (path === "~")
|
|
13787
|
+
return homedir5();
|
|
13788
|
+
if (path.startsWith("~/"))
|
|
13789
|
+
return join20(homedir5(), path.slice(2));
|
|
13790
|
+
return path;
|
|
13791
|
+
}
|
|
13792
|
+
function normalizeProjectPath(projectPath) {
|
|
13793
|
+
const expanded = expandHomePath(projectPath.trim());
|
|
13794
|
+
const resolvedPath = isAbsolute(expanded) ? normalize(expanded) : resolve(process.cwd(), expanded);
|
|
13795
|
+
return stripTrailingSeparator(resolvedPath);
|
|
13796
|
+
}
|
|
13258
13797
|
function readProjectContext(projectPath) {
|
|
13259
13798
|
const contextFiles = [];
|
|
13260
13799
|
const filesToRead = [
|
|
@@ -13272,33 +13811,33 @@ function readProjectContext(projectPath) {
|
|
|
13272
13811
|
"Dockerfile"
|
|
13273
13812
|
];
|
|
13274
13813
|
for (const f of filesToRead) {
|
|
13275
|
-
const p =
|
|
13276
|
-
if (
|
|
13814
|
+
const p = join20(projectPath, f);
|
|
13815
|
+
if (existsSync15(p)) {
|
|
13277
13816
|
try {
|
|
13278
|
-
const content =
|
|
13817
|
+
const content = readFileSync12(p, "utf-8");
|
|
13279
13818
|
contextFiles.push({ name: f, content: content.slice(0, 2000) });
|
|
13280
13819
|
} catch {}
|
|
13281
13820
|
}
|
|
13282
13821
|
}
|
|
13283
13822
|
let dirStructure = "";
|
|
13284
13823
|
try {
|
|
13285
|
-
const items =
|
|
13824
|
+
const items = readdirSync4(projectPath, { withFileTypes: true }).filter((d) => !d.name.startsWith(".") && d.name !== "node_modules" && d.name !== "__pycache__").slice(0, 30);
|
|
13286
13825
|
dirStructure = items.map((d) => `${d.isDirectory() ? "\uD83D\uDCC1" : "\uD83D\uDCC4"} ${d.name}`).join(`
|
|
13287
13826
|
`);
|
|
13288
13827
|
} catch {}
|
|
13289
13828
|
let srcStructure = "";
|
|
13290
|
-
const srcDir =
|
|
13291
|
-
if (
|
|
13829
|
+
const srcDir = join20(projectPath, "src");
|
|
13830
|
+
if (existsSync15(srcDir)) {
|
|
13292
13831
|
try {
|
|
13293
13832
|
const scanDir = (dir, prefix, depth) => {
|
|
13294
13833
|
if (depth > 2)
|
|
13295
13834
|
return [];
|
|
13296
13835
|
const lines = [];
|
|
13297
|
-
const items =
|
|
13836
|
+
const items = readdirSync4(dir, { withFileTypes: true }).filter((d) => !d.name.startsWith(".")).slice(0, 20);
|
|
13298
13837
|
for (const item of items) {
|
|
13299
13838
|
lines.push(`${prefix}${item.isDirectory() ? "\uD83D\uDCC1" : "\uD83D\uDCC4"} ${item.name}`);
|
|
13300
13839
|
if (item.isDirectory()) {
|
|
13301
|
-
lines.push(...scanDir(
|
|
13840
|
+
lines.push(...scanDir(join20(dir, item.name), prefix + " ", depth + 1));
|
|
13302
13841
|
}
|
|
13303
13842
|
}
|
|
13304
13843
|
return lines;
|
|
@@ -13332,18 +13871,18 @@ ${f.content}
|
|
|
13332
13871
|
return context;
|
|
13333
13872
|
}
|
|
13334
13873
|
function getProjectsDir() {
|
|
13335
|
-
return
|
|
13874
|
+
return join20(getHelixDir(), "projects");
|
|
13336
13875
|
}
|
|
13337
13876
|
function saveProjectProfile(profile) {
|
|
13338
|
-
const dir =
|
|
13339
|
-
|
|
13340
|
-
|
|
13877
|
+
const dir = join20(getProjectsDir(), profile.name);
|
|
13878
|
+
mkdirSync6(dir, { recursive: true });
|
|
13879
|
+
writeFileSync12(join20(dir, "profile.json"), JSON.stringify(profile, null, 2));
|
|
13341
13880
|
}
|
|
13342
13881
|
async function projectSetupCommand(projectPath, options) {
|
|
13343
13882
|
const verbose = options.verbose ?? false;
|
|
13344
13883
|
const dryRun = options.dryRun ?? false;
|
|
13345
|
-
const resolvedPath =
|
|
13346
|
-
if (!
|
|
13884
|
+
const resolvedPath = normalizeProjectPath(projectPath);
|
|
13885
|
+
if (!existsSync15(resolvedPath)) {
|
|
13347
13886
|
console.error(` ✗ Path not found: ${resolvedPath}`);
|
|
13348
13887
|
process.exit(1);
|
|
13349
13888
|
}
|
|
@@ -13402,19 +13941,58 @@ async function projectSetupCommand(projectPath, options) {
|
|
|
13402
13941
|
}
|
|
13403
13942
|
}
|
|
13404
13943
|
if (!dryRun) {
|
|
13944
|
+
const analyzedAt = new Date().toISOString();
|
|
13405
13945
|
const profile = {
|
|
13406
13946
|
name: analysis.name,
|
|
13407
13947
|
path: resolvedPath,
|
|
13408
13948
|
description: analysis.description,
|
|
13409
13949
|
techStack: analysis.techStack,
|
|
13410
13950
|
domains: analysis.domains,
|
|
13411
|
-
analyzedAt
|
|
13951
|
+
analyzedAt,
|
|
13412
13952
|
matchedSkills: analysis.matchedSkills,
|
|
13413
13953
|
gaps: analysis.gaps,
|
|
13414
13954
|
recommendations: analysis.recommendations,
|
|
13415
13955
|
status: "analyzed"
|
|
13416
13956
|
};
|
|
13417
13957
|
saveProjectProfile(profile);
|
|
13958
|
+
const activationTraceId = `activation_project_${analysis.name}_${Date.now()}`;
|
|
13959
|
+
const activationTrace = {
|
|
13960
|
+
id: activationTraceId,
|
|
13961
|
+
timestamp: analyzedAt,
|
|
13962
|
+
provenance: "project-analysis",
|
|
13963
|
+
sourceId: resolvedPath,
|
|
13964
|
+
projectId: analysis.name,
|
|
13965
|
+
projectPath: resolvedPath,
|
|
13966
|
+
activatedSkillIds: analysis.matchedSkills.map((skill) => skill.slug),
|
|
13967
|
+
relevantSkillIds: analysis.matchedSkills.map((skill) => skill.slug),
|
|
13968
|
+
reasonSummary: "project-analysis skill match and capability scan",
|
|
13969
|
+
contextSummary: analysis.description,
|
|
13970
|
+
gapAreas: analysis.gaps.map((gap) => gap.area),
|
|
13971
|
+
recommendations: analysis.recommendations,
|
|
13972
|
+
traceVersion: "0.1.0"
|
|
13973
|
+
};
|
|
13974
|
+
appendActivationTrace(activationTrace);
|
|
13975
|
+
analysis.gaps.forEach((gap, index) => {
|
|
13976
|
+
const signal = {
|
|
13977
|
+
id: `pressure_project_${analysis.name}_${index}_${Date.now()}`,
|
|
13978
|
+
kind: `gap:${gap.area}`,
|
|
13979
|
+
provenance: "project-analysis-native",
|
|
13980
|
+
sourceType: "project-analysis",
|
|
13981
|
+
sourceId: resolvedPath,
|
|
13982
|
+
projectId: analysis.name,
|
|
13983
|
+
projectPath: resolvedPath,
|
|
13984
|
+
detectedAt: analyzedAt,
|
|
13985
|
+
severity: gap.priority === "high" ? 0.95 : gap.priority === "medium" ? 0.75 : 0.55,
|
|
13986
|
+
priority: gap.priority,
|
|
13987
|
+
capability: gap.area,
|
|
13988
|
+
description: gap.description,
|
|
13989
|
+
suggestedAction: gap.suggestedAction,
|
|
13990
|
+
relatedActivationTraceId: activationTraceId,
|
|
13991
|
+
skillIds: analysis.matchedSkills.map((skill) => skill.slug),
|
|
13992
|
+
status: "open"
|
|
13993
|
+
};
|
|
13994
|
+
appendPressureSignal(signal);
|
|
13995
|
+
});
|
|
13418
13996
|
console.log(`
|
|
13419
13997
|
✓ Project profile saved to ~/.helix/projects/${analysis.name}/`);
|
|
13420
13998
|
console.log(` Next: Run "helixevo specialize --project ${analysis.name}" to create project-specific skills`);
|
|
@@ -13428,95 +14006,9 @@ async function projectSetupCommand(projectPath, options) {
|
|
|
13428
14006
|
console.log();
|
|
13429
14007
|
}
|
|
13430
14008
|
|
|
13431
|
-
// src/utils/update-check.ts
|
|
13432
|
-
import { readFileSync as readFileSync12, writeFileSync as writeFileSync12, existsSync as existsSync15, mkdirSync as mkdirSync6 } from "node:fs";
|
|
13433
|
-
import { join as join19 } from "node:path";
|
|
13434
|
-
import { homedir as homedir4 } from "node:os";
|
|
13435
|
-
var HELIX_DIR2 = join19(homedir4(), ".helix");
|
|
13436
|
-
var CACHE_PATH = join19(HELIX_DIR2, "update-check.json");
|
|
13437
|
-
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;
|
|
13438
|
-
var REGISTRY_URL = "https://registry.npmjs.org/helixevo/latest";
|
|
13439
|
-
function readCache() {
|
|
13440
|
-
try {
|
|
13441
|
-
if (!existsSync15(CACHE_PATH))
|
|
13442
|
-
return null;
|
|
13443
|
-
return JSON.parse(readFileSync12(CACHE_PATH, "utf-8"));
|
|
13444
|
-
} catch {
|
|
13445
|
-
return null;
|
|
13446
|
-
}
|
|
13447
|
-
}
|
|
13448
|
-
function writeCache(cache) {
|
|
13449
|
-
try {
|
|
13450
|
-
if (!existsSync15(HELIX_DIR2))
|
|
13451
|
-
mkdirSync6(HELIX_DIR2, { recursive: true });
|
|
13452
|
-
writeFileSync12(CACHE_PATH, JSON.stringify(cache));
|
|
13453
|
-
} catch {}
|
|
13454
|
-
}
|
|
13455
|
-
function compareVersions(current, latest) {
|
|
13456
|
-
const c = current.split(".").map(Number);
|
|
13457
|
-
const l = latest.split(".").map(Number);
|
|
13458
|
-
for (let i = 0;i < 3; i++) {
|
|
13459
|
-
if ((l[i] ?? 0) > (c[i] ?? 0))
|
|
13460
|
-
return true;
|
|
13461
|
-
if ((l[i] ?? 0) < (c[i] ?? 0))
|
|
13462
|
-
return false;
|
|
13463
|
-
}
|
|
13464
|
-
return false;
|
|
13465
|
-
}
|
|
13466
|
-
async function fetchLatestVersion() {
|
|
13467
|
-
try {
|
|
13468
|
-
const controller = new AbortController;
|
|
13469
|
-
const timeout = setTimeout(() => controller.abort(), 3000);
|
|
13470
|
-
const res = await fetch(REGISTRY_URL, { signal: controller.signal });
|
|
13471
|
-
clearTimeout(timeout);
|
|
13472
|
-
if (!res.ok)
|
|
13473
|
-
return null;
|
|
13474
|
-
const data = await res.json();
|
|
13475
|
-
return data.version ?? null;
|
|
13476
|
-
} catch {
|
|
13477
|
-
return null;
|
|
13478
|
-
}
|
|
13479
|
-
}
|
|
13480
|
-
async function checkForUpdates() {
|
|
13481
|
-
try {
|
|
13482
|
-
const cache = readCache();
|
|
13483
|
-
if (cache && Date.now() - cache.lastCheck < CHECK_INTERVAL_MS) {
|
|
13484
|
-
if (compareVersions(VERSION, cache.latestVersion)) {
|
|
13485
|
-
printUpdateBanner(cache.latestVersion);
|
|
13486
|
-
}
|
|
13487
|
-
return;
|
|
13488
|
-
}
|
|
13489
|
-
const latest = await fetchLatestVersion();
|
|
13490
|
-
if (!latest)
|
|
13491
|
-
return;
|
|
13492
|
-
writeCache({ lastCheck: Date.now(), latestVersion: latest });
|
|
13493
|
-
if (compareVersions(VERSION, latest)) {
|
|
13494
|
-
printUpdateBanner(latest);
|
|
13495
|
-
}
|
|
13496
|
-
} catch {}
|
|
13497
|
-
}
|
|
13498
|
-
function printUpdateBanner(latestVersion) {
|
|
13499
|
-
const yellow = "\x1B[33m";
|
|
13500
|
-
const green = "\x1B[32m";
|
|
13501
|
-
const cyan = "\x1B[36m";
|
|
13502
|
-
const bold = "\x1B[1m";
|
|
13503
|
-
const dim = "\x1B[2m";
|
|
13504
|
-
const reset = "\x1B[0m";
|
|
13505
|
-
console.log();
|
|
13506
|
-
console.log(`${yellow} ╭──────────────────────────────────────────────╮${reset}`);
|
|
13507
|
-
console.log(`${yellow} │ │${reset}`);
|
|
13508
|
-
console.log(`${yellow} │ ${bold}Update available!${reset}${yellow} ${dim}v${VERSION}${reset}${yellow} → ${green}${bold}v${latestVersion}${reset}${yellow} │${reset}`);
|
|
13509
|
-
console.log(`${yellow} │ │${reset}`);
|
|
13510
|
-
console.log(`${yellow} │ ${reset}Run ${cyan}npm install -g helixevo@latest${reset}${yellow} │${reset}`);
|
|
13511
|
-
console.log(`${yellow} │ ${reset}to update${yellow} │${reset}`);
|
|
13512
|
-
console.log(`${yellow} │ │${reset}`);
|
|
13513
|
-
console.log(`${yellow} ╰──────────────────────────────────────────────╯${reset}`);
|
|
13514
|
-
console.log();
|
|
13515
|
-
}
|
|
13516
|
-
|
|
13517
14009
|
// src/cli.ts
|
|
13518
|
-
import { join as
|
|
13519
|
-
import { homedir as
|
|
14010
|
+
import { join as join21 } from "node:path";
|
|
14011
|
+
import { homedir as homedir6 } from "node:os";
|
|
13520
14012
|
import { existsSync as existsSync16, readFileSync as readFileSync13, rmSync as rmSync3 } from "node:fs";
|
|
13521
14013
|
var program2 = new Command;
|
|
13522
14014
|
program2.name("helixevo").description("Self-evolving skill ecosystem for AI agents").version(VERSION).addHelpText("after", `
|
|
@@ -13545,9 +14037,9 @@ program2.command("generalize").description("Promote cross-skill patterns to high
|
|
|
13545
14037
|
program2.command("specialize").description("Create project-specific skills ↓ --project <name> [--dry-run] [--verbose]").requiredOption("--project <name>", "Project name").option("--dry-run", "Show candidates without applying").option("--verbose", "Show detailed analysis").action(specializeCommand);
|
|
13546
14038
|
program2.command("graph").description("Skill network [--mermaid] [--obsidian <path>] [--rebuild] [--optimize]").option("--mermaid", "Render as Mermaid diagram in browser").option("--rebuild", "Force rebuild (re-infer relationships via LLM)").option("--obsidian <path>", "Sync to Obsidian vault at path").option("--optimize", "Run network optimization (merge/split/conflict detection)").option("--verbose", "Show detailed analysis").action(graphCommand);
|
|
13547
14039
|
program2.command("research").description("Proactive research via web [--project <path>] [--dry-run] [--verbose]").option("--project <path>", "Project path for goal extraction").option("--dry-run", "Show discoveries without creating skills").option("--verbose", "Show detailed research steps").option("--max-hypotheses <n>", "Max hypotheses to test", "3").action(researchCommand);
|
|
13548
|
-
program2.command("dashboard").description("Open web dashboard at http://localhost:3847").option("--background", "Run in background (detach from terminal)").option("--stop", "Stop a background dashboard").action(async (options) => {
|
|
14040
|
+
program2.command("dashboard").description("Open web dashboard at http://localhost:3847").option("--background", "Run in background (detach from terminal)").option("--stop", "Stop a background dashboard").option("--no-auto-update", "Skip automatic update check before launching the dashboard").action(async (options) => {
|
|
13549
14041
|
if (options.stop) {
|
|
13550
|
-
const pidFile =
|
|
14042
|
+
const pidFile = join21(homedir6(), ".helix", "dashboard.pid");
|
|
13551
14043
|
if (existsSync16(pidFile)) {
|
|
13552
14044
|
const pid = parseInt(readFileSync13(pidFile, "utf-8").trim());
|
|
13553
14045
|
try {
|
|
@@ -13560,7 +14052,7 @@ program2.command("dashboard").description("Open web dashboard at http://localhos
|
|
|
13560
14052
|
}
|
|
13561
14053
|
return;
|
|
13562
14054
|
}
|
|
13563
|
-
dashboardCommand(options);
|
|
14055
|
+
await dashboardCommand(options);
|
|
13564
14056
|
});
|
|
13565
14057
|
program2.command("status").description("Show frontier, skills, failures, and network health").action(statusCommand);
|
|
13566
14058
|
program2.command("report").description("Evolution report [--days <n>] [--output <path>]").option("--days <n>", "Report period in days", "1").option("--output <path>", "Output path for report").action(reportCommand);
|