helixevo 0.2.41 → 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/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 runClaude(prompt, args) {
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
- reject(new Error(`claude exited with code ${code}: ${stderr.slice(0, 500)}`));
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 join4 } from "node:path";
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 join3, dirname as dirname2 } from "node:path";
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(join3(dirname2(fileURLToPath(import.meta.url)), "..", "package.json"));
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(join4(sgDir, "config.json"))) {
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
- join4(homedir2(), ".agents", "skills"),
9630
- join4(homedir2(), ".craft-agent", "workspaces")
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: readdirSync2 } = await import("node:fs");
9637
- const workspaces = readdirSync2(p, { withFileTypes: true }).filter((d) => d.isDirectory() && !d.name.startsWith("."));
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 = join4(p, ws.name, "skills");
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 = join4(generalDir, skill.slug);
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: `f_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`,
10037
+ id: failureId,
9752
10038
  sessionId,
9753
- timestamp: new Date().toISOString(),
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 join7 } from "node:path";
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 join5 } from "node:path";
10220
- var CANARY_DIR = join5(getHelixDir(), "canary");
10221
- var BACKUPS_DIR = join5(getHelixDir(), "backups");
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 join5(getHelixDir(), "canary-registry.json");
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 = join5(BACKUPS_DIR, `${slug}_${version}_${Date.now()}`);
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 join6 } from "node:path";
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 = join6(getGeneralSkillsPath(), candidate.suggestedName);
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 = join7(getGeneralSkillsPath(), skillSlug2);
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: generateIterationId(),
10644
- timestamp: new Date().toISOString(),
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 join8 } from "node:path";
10709
- var BUFFER_PATH = () => join8(getHelixDir(), "knowledge-buffer.json");
10710
- var DRAFTS_DIR = () => join8(getHelixDir(), "drafts");
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 = join8(DRAFTS_DIR(), draft.skillName);
11125
+ const draftDir = join9(DRAFTS_DIR(), draft.skillName);
10768
11126
  ensureDir(draftDir);
10769
- writeFileSync5(join8(draftDir, "SKILL.md"), draft.skillMd);
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 = join8(DRAFTS_DIR(), draft.skillName);
11141
+ const draftDir = join9(DRAFTS_DIR(), draft.skillName);
10784
11142
  ensureDir(draftDir);
10785
- writeFileSync5(join8(draftDir, "SKILL.md"), draft.skillMd);
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 join9 } from "node:path";
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 ?? join9(getHelixDir(), "reports", `${date}.md`);
10970
- ensureDir(join9(getHelixDir(), "reports"));
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 join10 } from "node:path";
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 = join10(getGeneralSkillsPath(), candidate.suggestedName);
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 join11 } from "node:path";
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 = join11(process.cwd(), ".helix", "skills");
11224
- const skillDir = join11(projectSkillsDir, candidate.suggestedName);
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 join13 } from "node:path";
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 join12 } from "node:path";
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 = join12(vaultPath, "Skills");
11679
- const reportsDir = join12(vaultPath, "Reports");
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 = join12(skillsDir, `${node.id}.md`);
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(join12(vaultPath, "HelixEvo Index.md"), indexNote);
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(join12(reportsDir, `Evolution ${date}.md`), report);
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 = join13(tmpdir(), "helix-network.html");
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 join14 } from "node:path";
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 = join14(getGeneralSkillsPath(), hypothesis.skillName);
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 = join14(p, file);
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,8 +12808,8 @@ ${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 join16, dirname as dirname3 } from "node:path";
12447
- import { existsSync as existsSync11, cpSync as cpSync3, mkdirSync as mkdirSync5, readdirSync as readdirSync2, readFileSync as readFileSync9, rmSync as rmSync2, writeFileSync as writeFileSync10 } from "node:fs";
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
12814
  import { homedir as homedir4 } from "node:os";
12450
12815
  init_skills();
@@ -12452,10 +12817,10 @@ init_data();
12452
12817
 
12453
12818
  // src/utils/update-check.ts
12454
12819
  import { readFileSync as readFileSync8, writeFileSync as writeFileSync9, existsSync as existsSync10, mkdirSync as mkdirSync4 } from "node:fs";
12455
- import { join as join15 } from "node:path";
12820
+ import { join as join16 } from "node:path";
12456
12821
  import { homedir as homedir3 } from "node:os";
12457
- var HELIX_DIR2 = join15(homedir3(), ".helix");
12458
- var CACHE_PATH = join15(HELIX_DIR2, "update-check.json");
12822
+ var HELIX_DIR2 = join16(homedir3(), ".helix");
12823
+ var CACHE_PATH = join16(HELIX_DIR2, "update-check.json");
12459
12824
  var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;
12460
12825
  var REGISTRY_URL = "https://registry.npmjs.org/helixevo/latest";
12461
12826
  function readCache() {
@@ -12555,7 +12920,7 @@ function printUpdateBanner(currentVersion, latestVersion) {
12555
12920
 
12556
12921
  // src/commands/dashboard.ts
12557
12922
  var __filename = "/Users/tianchichen/Documents/GitHub/helixevo/src/commands/dashboard.ts";
12558
- var HELIX_DASHBOARD_DIR = join16(homedir4(), ".helix", "dashboard");
12923
+ var HELIX_DASHBOARD_DIR = join17(homedir4(), ".helix", "dashboard");
12559
12924
  var DASHBOARD_SKIP_AUTO_UPDATE_ENV = "HELIXEVO_DASHBOARD_SKIP_AUTO_UPDATE";
12560
12925
  async function dashboardCommand(options) {
12561
12926
  if (options.autoUpdate !== false && process.env[DASHBOARD_SKIP_AUTO_UPDATE_ENV] !== "1" && !findDevDashboard()) {
@@ -12572,7 +12937,7 @@ async function dashboardCommand(options) {
12572
12937
  console.error(" cd helixevo/dashboard && npm install && npx next dev --port 3847");
12573
12938
  process.exit(1);
12574
12939
  }
12575
- if (!existsSync11(join16(dir, "node_modules"))) {
12940
+ if (!existsSync11(join17(dir, "node_modules"))) {
12576
12941
  console.log(" Installing dashboard dependencies...");
12577
12942
  try {
12578
12943
  execSync2("npm install --no-audit --no-fund", { cwd: dir, stdio: "inherit" });
@@ -12585,7 +12950,7 @@ async function dashboardCommand(options) {
12585
12950
  }
12586
12951
  ensureSkillGraph();
12587
12952
  if (options.background) {
12588
- const logFile = join16(homedir4(), ".helix", "dashboard.log");
12953
+ const logFile = join17(homedir4(), ".helix", "dashboard.log");
12589
12954
  const out = __require("fs").openSync(logFile, "a");
12590
12955
  const err = __require("fs").openSync(logFile, "a");
12591
12956
  let currentVersion2 = VERSION;
@@ -12599,7 +12964,7 @@ async function dashboardCommand(options) {
12599
12964
  detached: true
12600
12965
  });
12601
12966
  child.unref();
12602
- writeFileSync10(join16(homedir4(), ".helix", "dashboard.pid"), String(child.pid));
12967
+ writeFileSync10(join17(homedir4(), ".helix", "dashboard.pid"), String(child.pid));
12603
12968
  console.log(` \uD83C\uDF10 HelixEvo Dashboard v${currentVersion2} running in background`);
12604
12969
  console.log(` http://localhost:3847`);
12605
12970
  console.log(` Logs: ${logFile}`);
@@ -12688,7 +13053,7 @@ function launchDashboard(dir, openBrowser) {
12688
13053
  \uD83D\uDD04 Restarting dashboard after update...
12689
13054
  `);
12690
13055
  setTimeout(() => {
12691
- const nextCache = join16(dir, ".next");
13056
+ const nextCache = join17(dir, ".next");
12692
13057
  if (existsSync11(nextCache)) {
12693
13058
  try {
12694
13059
  rmSync2(nextCache, { recursive: true });
@@ -12715,20 +13080,20 @@ function prepareDashboard() {
12715
13080
  const npmSource = findNpmDashboard();
12716
13081
  if (npmSource)
12717
13082
  return copyToHelix(npmSource);
12718
- if (existsSync11(join16(HELIX_DASHBOARD_DIR, "package.json"))) {
13083
+ if (existsSync11(join17(HELIX_DASHBOARD_DIR, "package.json"))) {
12719
13084
  return HELIX_DASHBOARD_DIR;
12720
13085
  }
12721
13086
  return null;
12722
13087
  }
12723
13088
  function findDevDashboard() {
12724
13089
  const candidates = [
12725
- join16(process.cwd(), "dashboard")
13090
+ join17(process.cwd(), "dashboard")
12726
13091
  ];
12727
13092
  const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
12728
- candidates.push(join16(home, "Documents", "GitHub", "helixevo", "dashboard"));
12729
- candidates.push(join16(home, "Documents", "GitHub", "skillgraph", "dashboard"));
13093
+ candidates.push(join17(home, "Documents", "GitHub", "helixevo", "dashboard"));
13094
+ candidates.push(join17(home, "Documents", "GitHub", "skillgraph", "dashboard"));
12730
13095
  for (const dir of candidates) {
12731
- if (existsSync11(join16(dir, "package.json")) && !dir.includes("node_modules")) {
13096
+ if (existsSync11(join17(dir, "package.json")) && !dir.includes("node_modules")) {
12732
13097
  return dir;
12733
13098
  }
12734
13099
  }
@@ -12739,15 +13104,15 @@ function findNpmDashboard() {
12739
13104
  try {
12740
13105
  const thisFile = typeof __filename !== "undefined" ? __filename : fileURLToPath2(import.meta.url);
12741
13106
  const pkgRoot = dirname3(dirname3(thisFile));
12742
- candidates.push(join16(pkgRoot, "dashboard"));
13107
+ candidates.push(join17(pkgRoot, "dashboard"));
12743
13108
  } catch {}
12744
13109
  try {
12745
13110
  const globalPrefix = execSync2("npm prefix -g", { encoding: "utf-8" }).trim();
12746
- candidates.push(join16(globalPrefix, "lib", "node_modules", "helixevo", "dashboard"));
12747
- candidates.push(join16(globalPrefix, "node_modules", "helixevo", "dashboard"));
13111
+ candidates.push(join17(globalPrefix, "lib", "node_modules", "helixevo", "dashboard"));
13112
+ candidates.push(join17(globalPrefix, "node_modules", "helixevo", "dashboard"));
12748
13113
  } catch {}
12749
13114
  for (const dir of candidates) {
12750
- if (existsSync11(join16(dir, "package.json"))) {
13115
+ if (existsSync11(join17(dir, "package.json"))) {
12751
13116
  return dir;
12752
13117
  }
12753
13118
  }
@@ -12755,7 +13120,7 @@ function findNpmDashboard() {
12755
13120
  }
12756
13121
  function getInstalledDashboardVersion() {
12757
13122
  try {
12758
- const versionFile = join16(HELIX_DASHBOARD_DIR, ".helixevo-version");
13123
+ const versionFile = join17(HELIX_DASHBOARD_DIR, ".helixevo-version");
12759
13124
  if (!existsSync11(versionFile))
12760
13125
  return null;
12761
13126
  return readFileSync9(versionFile, "utf-8").trim();
@@ -12766,7 +13131,7 @@ function getInstalledDashboardVersion() {
12766
13131
  function copyToHelix(sourceDir) {
12767
13132
  let sourceVersion = VERSION;
12768
13133
  try {
12769
- const srcRoot = join16(sourceDir, "..", "package.json");
13134
+ const srcRoot = join17(sourceDir, "..", "package.json");
12770
13135
  const pkg2 = JSON.parse(readFileSync9(srcRoot, "utf-8"));
12771
13136
  if (pkg2.name === "helixevo" && pkg2.version)
12772
13137
  sourceVersion = pkg2.version;
@@ -12783,34 +13148,34 @@ function copyToHelix(sourceDir) {
12783
13148
  mkdirSync5(HELIX_DASHBOARD_DIR, { recursive: true });
12784
13149
  let depsChanged = true;
12785
13150
  try {
12786
- const srcDeps = readFileSync9(join16(sourceDir, "package.json"), "utf-8");
12787
- const dstDeps = readFileSync9(join16(HELIX_DASHBOARD_DIR, "package.json"), "utf-8");
13151
+ const srcDeps = readFileSync9(join17(sourceDir, "package.json"), "utf-8");
13152
+ const dstDeps = readFileSync9(join17(HELIX_DASHBOARD_DIR, "package.json"), "utf-8");
12788
13153
  const srcPkg = JSON.parse(srcDeps);
12789
13154
  const dstPkg = JSON.parse(dstDeps);
12790
13155
  depsChanged = JSON.stringify(srcPkg.dependencies) !== JSON.stringify(dstPkg.dependencies) || JSON.stringify(srcPkg.devDependencies) !== JSON.stringify(dstPkg.devDependencies);
12791
13156
  } catch {
12792
13157
  depsChanged = true;
12793
13158
  }
12794
- const items = readdirSync2(sourceDir, { withFileTypes: true });
13159
+ const items = readdirSync3(sourceDir, { withFileTypes: true });
12795
13160
  for (const item of items) {
12796
13161
  if (item.name === "node_modules" || item.name === ".next" || item.name === "package-lock.json" || item.name === ".env.local")
12797
13162
  continue;
12798
- const src = join16(sourceDir, item.name);
12799
- const dest = join16(HELIX_DASHBOARD_DIR, item.name);
13163
+ const src = join17(sourceDir, item.name);
13164
+ const dest = join17(HELIX_DASHBOARD_DIR, item.name);
12800
13165
  cpSync3(src, dest, { recursive: true });
12801
13166
  }
12802
13167
  if (depsChanged) {
12803
- const oldModules = join16(HELIX_DASHBOARD_DIR, "node_modules");
13168
+ const oldModules = join17(HELIX_DASHBOARD_DIR, "node_modules");
12804
13169
  if (existsSync11(oldModules))
12805
13170
  rmSync2(oldModules, { recursive: true });
12806
- const oldLock = join16(HELIX_DASHBOARD_DIR, "package-lock.json");
13171
+ const oldLock = join17(HELIX_DASHBOARD_DIR, "package-lock.json");
12807
13172
  if (existsSync11(oldLock))
12808
13173
  rmSync2(oldLock);
12809
13174
  }
12810
- const nextCache = join16(HELIX_DASHBOARD_DIR, ".next");
13175
+ const nextCache = join17(HELIX_DASHBOARD_DIR, ".next");
12811
13176
  if (existsSync11(nextCache))
12812
13177
  rmSync2(nextCache, { recursive: true });
12813
- writeFileSync10(join16(HELIX_DASHBOARD_DIR, ".helixevo-version"), sourceVersion);
13178
+ writeFileSync10(join17(HELIX_DASHBOARD_DIR, ".helixevo-version"), sourceVersion);
12814
13179
  return HELIX_DASHBOARD_DIR;
12815
13180
  }
12816
13181
  function ensureSkillGraph() {
@@ -12852,7 +13217,7 @@ function ensureSkillGraph() {
12852
13217
  }
12853
13218
 
12854
13219
  // src/commands/watch.ts
12855
- import { join as join18 } from "node:path";
13220
+ import { join as join19 } from "node:path";
12856
13221
  import { existsSync as existsSync14 } from "node:fs";
12857
13222
 
12858
13223
  // src/core/auto-capture.ts
@@ -12999,9 +13364,9 @@ init_data();
12999
13364
  init_config();
13000
13365
  init_data();
13001
13366
  import { readFileSync as readFileSync11, writeFileSync as writeFileSync11, existsSync as existsSync13 } from "node:fs";
13002
- import { join as join17 } from "node:path";
13367
+ import { join as join18 } from "node:path";
13003
13368
  function getMetricsPath() {
13004
- return join17(getHelixDir(), "metrics.json");
13369
+ return join18(getHelixDir(), "metrics.json");
13005
13370
  }
13006
13371
  function loadMetrics() {
13007
13372
  const path = getMetricsPath();
@@ -13188,7 +13553,7 @@ async function watchCommand(options) {
13188
13553
  const verbose = options.verbose ?? false;
13189
13554
  const autoEvolve = options.evolve !== false;
13190
13555
  const project = options.project ?? null;
13191
- const eventsPath = options.events ?? join18(process.cwd(), "events.jsonl");
13556
+ const eventsPath = options.events ?? join19(process.cwd(), "events.jsonl");
13192
13557
  console.log(`\uD83E\uDDEC HelixEvo Watch Mode — Always-On Learning
13193
13558
  `);
13194
13559
  console.log(` Events: ${eventsPath}`);
@@ -13343,10 +13708,12 @@ async function metricsCommand(options) {
13343
13708
  }
13344
13709
 
13345
13710
  // src/commands/project-setup.ts
13711
+ init_data();
13346
13712
  init_skills();
13347
13713
  init_llm();
13348
- import { join as join19 } from "node:path";
13349
- import { existsSync as existsSync15, readFileSync as readFileSync12, writeFileSync as writeFileSync12, mkdirSync as mkdirSync6, readdirSync as readdirSync3 } from "node:fs";
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";
13350
13717
 
13351
13718
  // src/prompts/project-analysis.ts
13352
13719
  function buildProjectAnalysisPrompt(projectContext, skills) {
@@ -13410,6 +13777,23 @@ Return JSON:
13410
13777
 
13411
13778
  // src/commands/project-setup.ts
13412
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
+ }
13413
13797
  function readProjectContext(projectPath) {
13414
13798
  const contextFiles = [];
13415
13799
  const filesToRead = [
@@ -13427,7 +13811,7 @@ function readProjectContext(projectPath) {
13427
13811
  "Dockerfile"
13428
13812
  ];
13429
13813
  for (const f of filesToRead) {
13430
- const p = join19(projectPath, f);
13814
+ const p = join20(projectPath, f);
13431
13815
  if (existsSync15(p)) {
13432
13816
  try {
13433
13817
  const content = readFileSync12(p, "utf-8");
@@ -13437,23 +13821,23 @@ function readProjectContext(projectPath) {
13437
13821
  }
13438
13822
  let dirStructure = "";
13439
13823
  try {
13440
- const items = readdirSync3(projectPath, { withFileTypes: true }).filter((d) => !d.name.startsWith(".") && d.name !== "node_modules" && d.name !== "__pycache__").slice(0, 30);
13824
+ const items = readdirSync4(projectPath, { withFileTypes: true }).filter((d) => !d.name.startsWith(".") && d.name !== "node_modules" && d.name !== "__pycache__").slice(0, 30);
13441
13825
  dirStructure = items.map((d) => `${d.isDirectory() ? "\uD83D\uDCC1" : "\uD83D\uDCC4"} ${d.name}`).join(`
13442
13826
  `);
13443
13827
  } catch {}
13444
13828
  let srcStructure = "";
13445
- const srcDir = join19(projectPath, "src");
13829
+ const srcDir = join20(projectPath, "src");
13446
13830
  if (existsSync15(srcDir)) {
13447
13831
  try {
13448
13832
  const scanDir = (dir, prefix, depth) => {
13449
13833
  if (depth > 2)
13450
13834
  return [];
13451
13835
  const lines = [];
13452
- const items = readdirSync3(dir, { withFileTypes: true }).filter((d) => !d.name.startsWith(".")).slice(0, 20);
13836
+ const items = readdirSync4(dir, { withFileTypes: true }).filter((d) => !d.name.startsWith(".")).slice(0, 20);
13453
13837
  for (const item of items) {
13454
13838
  lines.push(`${prefix}${item.isDirectory() ? "\uD83D\uDCC1" : "\uD83D\uDCC4"} ${item.name}`);
13455
13839
  if (item.isDirectory()) {
13456
- lines.push(...scanDir(join19(dir, item.name), prefix + " ", depth + 1));
13840
+ lines.push(...scanDir(join20(dir, item.name), prefix + " ", depth + 1));
13457
13841
  }
13458
13842
  }
13459
13843
  return lines;
@@ -13487,17 +13871,17 @@ ${f.content}
13487
13871
  return context;
13488
13872
  }
13489
13873
  function getProjectsDir() {
13490
- return join19(getHelixDir(), "projects");
13874
+ return join20(getHelixDir(), "projects");
13491
13875
  }
13492
13876
  function saveProjectProfile(profile) {
13493
- const dir = join19(getProjectsDir(), profile.name);
13877
+ const dir = join20(getProjectsDir(), profile.name);
13494
13878
  mkdirSync6(dir, { recursive: true });
13495
- writeFileSync12(join19(dir, "profile.json"), JSON.stringify(profile, null, 2));
13879
+ writeFileSync12(join20(dir, "profile.json"), JSON.stringify(profile, null, 2));
13496
13880
  }
13497
13881
  async function projectSetupCommand(projectPath, options) {
13498
13882
  const verbose = options.verbose ?? false;
13499
13883
  const dryRun = options.dryRun ?? false;
13500
- const resolvedPath = join19(process.cwd(), projectPath).replace(/\/$/, "");
13884
+ const resolvedPath = normalizeProjectPath(projectPath);
13501
13885
  if (!existsSync15(resolvedPath)) {
13502
13886
  console.error(` ✗ Path not found: ${resolvedPath}`);
13503
13887
  process.exit(1);
@@ -13557,19 +13941,58 @@ async function projectSetupCommand(projectPath, options) {
13557
13941
  }
13558
13942
  }
13559
13943
  if (!dryRun) {
13944
+ const analyzedAt = new Date().toISOString();
13560
13945
  const profile = {
13561
13946
  name: analysis.name,
13562
13947
  path: resolvedPath,
13563
13948
  description: analysis.description,
13564
13949
  techStack: analysis.techStack,
13565
13950
  domains: analysis.domains,
13566
- analyzedAt: new Date().toISOString(),
13951
+ analyzedAt,
13567
13952
  matchedSkills: analysis.matchedSkills,
13568
13953
  gaps: analysis.gaps,
13569
13954
  recommendations: analysis.recommendations,
13570
13955
  status: "analyzed"
13571
13956
  };
13572
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
+ });
13573
13996
  console.log(`
13574
13997
  ✓ Project profile saved to ~/.helix/projects/${analysis.name}/`);
13575
13998
  console.log(` Next: Run "helixevo specialize --project ${analysis.name}" to create project-specific skills`);
@@ -13584,8 +14007,8 @@ async function projectSetupCommand(projectPath, options) {
13584
14007
  }
13585
14008
 
13586
14009
  // src/cli.ts
13587
- import { join as join20 } from "node:path";
13588
- import { homedir as homedir5 } from "node:os";
14010
+ import { join as join21 } from "node:path";
14011
+ import { homedir as homedir6 } from "node:os";
13589
14012
  import { existsSync as existsSync16, readFileSync as readFileSync13, rmSync as rmSync3 } from "node:fs";
13590
14013
  var program2 = new Command;
13591
14014
  program2.name("helixevo").description("Self-evolving skill ecosystem for AI agents").version(VERSION).addHelpText("after", `
@@ -13616,7 +14039,7 @@ program2.command("graph").description("Skill network [--mermaid] [--obsidian <pa
13616
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);
13617
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) => {
13618
14041
  if (options.stop) {
13619
- const pidFile = join20(homedir5(), ".helix", "dashboard.pid");
14042
+ const pidFile = join21(homedir6(), ".helix", "dashboard.pid");
13620
14043
  if (existsSync16(pidFile)) {
13621
14044
  const pid = parseInt(readFileSync13(pidFile, "utf-8").trim());
13622
14045
  try {