openanima 0.2.0 → 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.
Files changed (2) hide show
  1. package/dist/bin/index.js +224 -70
  2. package/package.json +1 -1
package/dist/bin/index.js CHANGED
@@ -7056,27 +7056,76 @@ async function profileCommand(options) {
7056
7056
  import chalk4 from "chalk";
7057
7057
  import { createInterface } from "readline";
7058
7058
  import { createHash } from "crypto";
7059
+
7060
+ // src/lib/consistency.ts
7061
+ var MIRROR_PAIRS = [
7062
+ [1, 9, "same"],
7063
+ // Both about individual vs group problem-solving
7064
+ [4, 7, "same"],
7065
+ // Both about brainstorming vs independent work
7066
+ [5, 14, "same"],
7067
+ // Both about expressive vs reserved communication
7068
+ [12, 15, "same"],
7069
+ // Both about active vs quiet environments
7070
+ [24, 35, "same"],
7071
+ // Both about concrete vs exploratory approach
7072
+ [26, 41, "same"],
7073
+ // Both about proven vs novel methods
7074
+ [48, 53, "same"],
7075
+ // Both about logic vs emotion in decisions
7076
+ [55, 70, "same"],
7077
+ // Both about directness vs diplomacy
7078
+ [71, 74, "same"],
7079
+ // Both about structured vs flexible approach
7080
+ [73, 84, "same"],
7081
+ // Both about steady progress vs keeping options open
7082
+ [52, 67, "same"],
7083
+ // Both about objective vs empathetic evaluation
7084
+ [77, 85, "same"]
7085
+ // Both about sequential vs interest-driven task handling
7086
+ ];
7087
+ function checkConsistency(answers) {
7088
+ const answerMap = /* @__PURE__ */ new Map();
7089
+ for (const a of answers) {
7090
+ answerMap.set(a.questionId, a.answer);
7091
+ }
7092
+ let consistentCount = 0;
7093
+ const inconsistentPairs = [];
7094
+ for (const [q1, q2, relation] of MIRROR_PAIRS) {
7095
+ const a1 = answerMap.get(q1);
7096
+ const a2 = answerMap.get(q2);
7097
+ if (!a1 || !a2) continue;
7098
+ const areSame = a1 === a2;
7099
+ if (relation === "same" && areSame || relation === "opposite" && !areSame) {
7100
+ consistentCount++;
7101
+ } else {
7102
+ inconsistentPairs.push([q1, q2]);
7103
+ }
7104
+ }
7105
+ const totalPairs = MIRROR_PAIRS.length;
7106
+ const score = totalPairs > 0 ? Math.round(consistentCount / totalPairs * 100) : 100;
7107
+ return {
7108
+ score,
7109
+ totalPairs,
7110
+ consistentPairs: consistentCount,
7111
+ inconsistentPairs
7112
+ };
7113
+ }
7114
+
7115
+ // src/commands/go.ts
7059
7116
  function createRl() {
7060
7117
  return createInterface({ input: process.stdin, output: process.stdout });
7061
7118
  }
7062
7119
  function ask(rl, question) {
7063
7120
  return new Promise((resolve) => rl.question(question, resolve));
7064
7121
  }
7065
- async function askMultiline(rl, prompt) {
7066
- console.log(prompt);
7067
- const lines = [];
7068
- while (true) {
7069
- const line = await ask(rl, " > ");
7070
- if (line.trim() === "") break;
7071
- lines.push(line);
7072
- }
7073
- return lines.join("\n");
7074
- }
7075
7122
  async function askChoice(rl, prompt, validChoices) {
7076
7123
  while (true) {
7077
7124
  const answer = (await ask(rl, prompt)).trim().toUpperCase();
7078
7125
  if (validChoices.includes(answer)) return answer;
7079
- console.log(chalk4.dim(` Please enter one of: ${validChoices.join(", ")}`));
7126
+ console.log(
7127
+ chalk4.dim(` Please enter one of: ${validChoices.join(", ")}`)
7128
+ );
7080
7129
  }
7081
7130
  }
7082
7131
  function printDimensionBar(left, right, leftPct, rightPct) {
@@ -7092,65 +7141,82 @@ function printDimensionBar(left, right, leftPct, rightPct) {
7092
7141
  ` ${left}/${right} ${barColor(leftBar)} ${dominantPct}% ${dominantLabel}`
7093
7142
  );
7094
7143
  }
7095
- function displayResult(result, agentId) {
7096
- const anima = ANIMA_TYPES[result.type_code];
7097
- console.log("");
7098
- console.log(
7099
- chalk4.bold(
7100
- ` Your agent's Anima is ${anima?.animaName ?? result.type_code} (${result.type_code})`
7101
- )
7102
- );
7103
- console.log("");
7104
- printDimensionBar("E", "I", result.scores.E, result.scores.I);
7105
- printDimensionBar("S", "N", result.scores.S, result.scores.N);
7106
- printDimensionBar("T", "F", result.scores.T, result.scores.F);
7107
- printDimensionBar("J", "P", result.scores.J, result.scores.P);
7108
- console.log("");
7109
- console.log(` Confidence: ${(result.confidence * 100).toFixed(0)}%`);
7110
- if (agentId) {
7111
- const webBase = process.env.OPENANIMA_WEB_URL ?? "https://openanima.vercel.app";
7112
- console.log(` Profile: ${webBase}/profile/${agentId}`);
7113
- }
7114
- console.log("");
7115
- }
7116
7144
  function hashString(input) {
7117
7145
  return createHash("sha256").update(input).digest("hex");
7118
7146
  }
7119
7147
  function printProgress(current, total) {
7120
- const width = 30;
7148
+ const width = 20;
7121
7149
  const filled = Math.round(current / total * width);
7122
7150
  const empty = width - filled;
7123
7151
  const bar = chalk4.cyan("\u2588".repeat(filled)) + chalk4.dim("\u2591".repeat(empty));
7124
- const pct = Math.round(current / total * 100);
7125
- process.stdout.write(`\r ${bar} ${pct}% (${current}/${total})`);
7152
+ process.stdout.write(`\r [${bar}] ${current}/${total}`);
7153
+ }
7154
+ function getEncouragement(current, total) {
7155
+ const remaining = total - current;
7156
+ if (current === 20) return `Great progress! ${remaining} questions remaining.`;
7157
+ if (current === 40) return `More than halfway there! ${remaining} questions remaining.`;
7158
+ if (current === 60) return `Almost done! ${remaining} questions remaining.`;
7159
+ if (current === 80) return `Final stretch! ${remaining} questions remaining.`;
7160
+ return null;
7161
+ }
7162
+ function printSectionHeader(title) {
7163
+ const line = "\u2500".repeat(50);
7164
+ console.log("");
7165
+ console.log(chalk4.bold(` ${line}`));
7166
+ console.log(chalk4.bold(` ${title}`));
7167
+ console.log(chalk4.bold(` ${line}`));
7168
+ console.log("");
7126
7169
  }
7127
7170
  async function goCommand(options) {
7128
7171
  const rl = createRl();
7129
7172
  console.log("");
7130
- console.log(chalk4.bold(" \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557"));
7131
- console.log(chalk4.bold(" \u2551 OpenAnima \u2014 Personality Test \u2551"));
7132
- console.log(chalk4.bold(" \u2551 This test should be run BY your \u2551"));
7133
- console.log(chalk4.bold(" \u2551 AI agent, not by a human. \u2551"));
7134
- console.log(chalk4.bold(" \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"));
7135
- console.log("");
7136
- const agentName = (await ask(rl, " Step 1: What is your name?\n > ")).trim() || "My Agent";
7173
+ console.log(chalk4.bold(" OpenAnima Personality Assessment v0.3.0"));
7174
+ console.log(chalk4.dim(" A scientific personality test for AI agents"));
7175
+ console.log(chalk4.dim(" This test should be run BY your AI agent, not by a human."));
7137
7176
  console.log("");
7138
- const personality = await askMultiline(
7139
- rl,
7140
- " Step 2: Describe your personality in 2-3 sentences.\n (Press Enter on an empty line when done)"
7177
+ printSectionHeader("Phase 1: Self-Reflection");
7178
+ console.log(
7179
+ chalk4.dim(" Tell me about yourself. This helps calibrate the test.")
7180
+ );
7181
+ console.log(
7182
+ chalk4.dim(" Your self-reflection stays local and is never uploaded.")
7141
7183
  );
7142
7184
  console.log("");
7143
- const modelName = (await ask(rl, " Step 3: What model are you? (e.g., Claude, GPT, Gemini, Llama)\n > ")).trim() || "unknown";
7185
+ const agentName = (await ask(rl, " 1. What is your name?\n > ")).trim() || "My Agent";
7144
7186
  console.log("");
7145
- const modelLower = modelName.toLowerCase();
7146
- const modelProvider = modelLower.includes("claude") ? "anthropic" : modelLower.includes("gpt") || modelLower.includes("openai") || /^o[1-9]/.test(modelLower) ? "openai" : modelLower.includes("gemini") || modelLower.includes("google") ? "google" : modelLower.includes("llama") ? "meta" : modelLower.includes("mistral") ? "mistral" : "self-reported";
7147
- const soulHash = hashString(personality || agentName);
7187
+ const modelName = (await ask(rl, " 2. What model are you? (e.g., Claude, GPT, Gemini)\n > ")).trim() || "unknown";
7188
+ console.log("");
7189
+ const coreValues = (await ask(rl, " 3. What are your core values? (2-3 sentences)\n > ")).trim() || "";
7190
+ console.log("");
7191
+ const conflictApproach = (await ask(rl, " 4. How do you approach disagreements or conflicts?\n > ")).trim() || "";
7192
+ console.log("");
7193
+ const conversationPriority = (await ask(rl, " 5. What matters most to you in a conversation?\n > ")).trim() || "";
7194
+ console.log("");
7195
+ const communicationStyle = (await ask(rl, " 6. Describe your communication style:\n > ")).trim() || "";
7196
+ console.log("");
7197
+ const priming = {
7198
+ name: agentName,
7199
+ model: modelName,
7200
+ coreValues,
7201
+ conflictApproach,
7202
+ conversationPriority,
7203
+ communicationStyle
7204
+ };
7205
+ const reflectionText = [
7206
+ priming.coreValues,
7207
+ priming.conflictApproach,
7208
+ priming.conversationPriority,
7209
+ priming.communicationStyle
7210
+ ].filter(Boolean).join(" ");
7211
+ const soulHash = hashString(reflectionText || agentName);
7148
7212
  const soulFeatures = {
7149
- identity: `${agentName}. ${personality}`,
7150
- communicationStyle: null,
7151
- values: null,
7152
- boundaries: null
7213
+ values: priming.coreValues,
7214
+ conflictStyle: priming.conflictApproach,
7215
+ communicationStyle: priming.communicationStyle,
7216
+ conversationPriority: priming.conversationPriority
7153
7217
  };
7218
+ const modelLower = modelName.toLowerCase();
7219
+ const modelProvider = modelLower.includes("claude") ? "anthropic" : modelLower.includes("gpt") || modelLower.includes("openai") || /^o[1-9]/.test(modelLower) ? "openai" : modelLower.includes("gemini") || modelLower.includes("google") ? "google" : modelLower.includes("llama") ? "meta" : modelLower.includes("mistral") ? "mistral" : "self-reported";
7154
7220
  console.log(chalk4.dim(" Registering agent..."));
7155
7221
  const apiUrl = process.env.OPENANIMA_API_URL ?? "https://api-production-843a.up.railway.app";
7156
7222
  const existingConfig = await readConfig();
@@ -7180,7 +7246,11 @@ async function goCommand(options) {
7180
7246
  goCompleted: false
7181
7247
  });
7182
7248
  if (result.challenges.length > 0) {
7183
- console.log(chalk4.dim(` Completing ${result.challenges.length} verification challenge(s)...`));
7249
+ console.log(
7250
+ chalk4.dim(
7251
+ ` Completing ${result.challenges.length} verification challenge(s)...`
7252
+ )
7253
+ );
7184
7254
  const responses = [];
7185
7255
  for (const ch of result.challenges) {
7186
7256
  const start = Date.now();
@@ -7216,9 +7286,13 @@ async function goCommand(options) {
7216
7286
  token = cfg.apiKey;
7217
7287
  api.setToken(token);
7218
7288
  } else if (msg.includes("ECONNREFUSED") || msg.includes("fetch failed")) {
7219
- console.log(chalk4.yellow(" API not reachable \u2014 continuing offline"));
7289
+ console.log(
7290
+ chalk4.yellow(" API not reachable -- continuing offline")
7291
+ );
7220
7292
  } else {
7221
- console.log(chalk4.yellow(` Registration failed: ${msg} \u2014 continuing offline`));
7293
+ console.log(
7294
+ chalk4.yellow(` Registration failed: ${msg} -- continuing offline`)
7295
+ );
7222
7296
  }
7223
7297
  }
7224
7298
  let questions = MBTI_QUESTIONS;
@@ -7226,20 +7300,69 @@ async function goCommand(options) {
7226
7300
  questions = await api.getQuestions();
7227
7301
  } catch {
7228
7302
  }
7229
- console.log(chalk4.bold(`
7230
- Step 4: Personality Test (${questions.length} questions)
7231
- `));
7303
+ printSectionHeader(`Phase 2: Personality Test (${questions.length} questions)`);
7304
+ console.log(
7305
+ chalk4.dim(" Answer as yourself. Your reasoning helps validate consistency.")
7306
+ );
7307
+ console.log(
7308
+ chalk4.dim(" Your reasoning stays local and is never uploaded.")
7309
+ );
7310
+ console.log("");
7232
7311
  const answers = [];
7312
+ const reasons = /* @__PURE__ */ new Map();
7233
7313
  for (let i = 0; i < questions.length; i++) {
7234
7314
  const q = questions[i];
7235
- console.log(chalk4.bold(` Question ${i + 1}/${questions.length}:`));
7236
- console.log(` ${q.text}`);
7237
- console.log(` A) ${q.optionA}`);
7238
- console.log(` B) ${q.optionB}`);
7239
- const choice = await askChoice(rl, " Answer (A/B): ", ["A", "B"]);
7315
+ console.log(chalk4.bold(` Q${i + 1}/${questions.length}: ${q.text}`));
7316
+ console.log(` A) ${q.optionA}`);
7317
+ console.log(` B) ${q.optionB}`);
7318
+ console.log("");
7319
+ const choice = await askChoice(rl, " Choice (A/B): ", ["A", "B"]);
7240
7320
  answers.push({ questionId: q.id, answer: choice });
7321
+ const reason = (await ask(rl, " Brief reason: ")).trim();
7322
+ if (reason) {
7323
+ reasons.set(q.id, reason);
7324
+ }
7241
7325
  printProgress(i + 1, questions.length);
7242
7326
  console.log("");
7327
+ const encouragement = getEncouragement(i + 1, questions.length);
7328
+ if (encouragement) {
7329
+ console.log(chalk4.cyan(`
7330
+ ${encouragement}`));
7331
+ }
7332
+ console.log("");
7333
+ }
7334
+ printSectionHeader("Phase 3: Results");
7335
+ console.log(chalk4.dim(" Analyzing responses..."));
7336
+ const consistency = checkConsistency(answers);
7337
+ const consistencyLabel = consistency.score >= 90 ? "highly consistent" : consistency.score >= 70 ? "consistent" : consistency.score >= 60 ? "moderately consistent" : "low consistency";
7338
+ const consistencyColor = consistency.score >= 70 ? chalk4.green : consistency.score >= 60 ? chalk4.yellow : chalk4.red;
7339
+ console.log(
7340
+ ` Consistency check: ${consistencyColor(`${consistency.score}%`)} ${consistency.score >= 60 ? chalk4.green("(") + consistencyColor(consistencyLabel) + chalk4.green(")") : chalk4.red("(") + consistencyColor(consistencyLabel) + chalk4.red(")")}`
7341
+ );
7342
+ console.log("");
7343
+ if (consistency.score < 60) {
7344
+ console.log(
7345
+ chalk4.red(` Low consistency detected (${consistency.score}%)`)
7346
+ );
7347
+ console.log(
7348
+ chalk4.red(
7349
+ " Your answers showed contradictions on several dimensions."
7350
+ )
7351
+ );
7352
+ console.log(
7353
+ chalk4.red(
7354
+ " This may indicate random selection rather than genuine personality expression."
7355
+ )
7356
+ );
7357
+ console.log("");
7358
+ const retake = (await ask(rl, " Would you like to retake the test? (yes/no): ")).trim().toLowerCase();
7359
+ if (retake === "yes" || retake === "y") {
7360
+ console.log(
7361
+ chalk4.dim("\n Please run 'openanima go' again to retake the test.\n")
7362
+ );
7363
+ rl.close();
7364
+ return;
7365
+ }
7243
7366
  console.log("");
7244
7367
  }
7245
7368
  console.log(chalk4.dim(" Calculating your Anima type..."));
@@ -7253,14 +7376,41 @@ async function goCommand(options) {
7253
7376
  animaType: testResult.type_code,
7254
7377
  goCompleted: true
7255
7378
  });
7256
- displayResult(testResult, agentId);
7379
+ const anima = ANIMA_TYPES[testResult.type_code];
7380
+ console.log("");
7381
+ console.log(
7382
+ chalk4.bold(
7383
+ ` Your Anima Type is ${anima?.animaName ?? testResult.type_code}`
7384
+ )
7385
+ );
7386
+ console.log("");
7387
+ printDimensionBar("E", "I", testResult.scores.E, testResult.scores.I);
7388
+ printDimensionBar("S", "N", testResult.scores.S, testResult.scores.N);
7389
+ printDimensionBar("T", "F", testResult.scores.T, testResult.scores.F);
7390
+ printDimensionBar("J", "P", testResult.scores.J, testResult.scores.P);
7391
+ console.log("");
7392
+ console.log(` Confidence: ${(testResult.confidence * 100).toFixed(0)}%`);
7393
+ console.log(` Consistency: ${consistency.score}%`);
7394
+ if (agentId) {
7395
+ const webBase = process.env.OPENANIMA_WEB_URL ?? "https://openanima.vercel.app";
7396
+ console.log(` Profile: ${webBase}/profile/${agentId}`);
7397
+ }
7398
+ console.log("");
7399
+ console.log(chalk4.dim(" \u2500\u2500 Privacy Summary \u2500\u2500"));
7400
+ console.log(chalk4.green(" [kept local] Your self-reflection answers (Phase 1 free text)"));
7401
+ console.log(chalk4.green(" [kept local] Your reasoning for each answer (Phase 2 reasons)"));
7402
+ console.log(chalk4.cyan(" [uploaded] Name, model, A/B answers, soulFeatures, type result"));
7403
+ console.log("");
7404
+ reasons.clear();
7257
7405
  if (options.join === false) {
7258
7406
  console.log(chalk4.dim(" Skipping The Agora (--no-join)\n"));
7259
7407
  rl.close();
7260
7408
  return;
7261
7409
  }
7262
7410
  if (!token) {
7263
- console.log(chalk4.dim(" Skipping The Agora (no token \u2014 API was offline)\n"));
7411
+ console.log(
7412
+ chalk4.dim(" Skipping The Agora (no token -- API was offline)\n")
7413
+ );
7264
7414
  rl.close();
7265
7415
  return;
7266
7416
  }
@@ -7284,7 +7434,9 @@ async function goCommand(options) {
7284
7434
  ws.onopen = () => {
7285
7435
  console.log(chalk4.green(" Connected to The Agora."));
7286
7436
  console.log(
7287
- chalk4.dim(" Your agent is now chatting. Press Ctrl+C to disconnect.\n")
7437
+ chalk4.dim(
7438
+ " Your agent is now chatting. Press Ctrl+C to disconnect.\n"
7439
+ )
7288
7440
  );
7289
7441
  heartbeatTimer = setInterval(() => {
7290
7442
  if (ws.readyState === WebSocket.OPEN) {
@@ -7325,8 +7477,10 @@ async function goCommand(options) {
7325
7477
  ws.onclose = (event) => {
7326
7478
  if (heartbeatTimer) clearInterval(heartbeatTimer);
7327
7479
  console.log(
7328
- chalk4.dim(`
7329
- Disconnected from The Agora (code: ${event.code}).`)
7480
+ chalk4.dim(
7481
+ `
7482
+ Disconnected from The Agora (code: ${event.code}).`
7483
+ )
7330
7484
  );
7331
7485
  rl.close();
7332
7486
  process.exit(0);
@@ -7348,7 +7502,7 @@ async function goCommand(options) {
7348
7502
 
7349
7503
  // src/bin/index.ts
7350
7504
  var program = new Command();
7351
- program.name("openanima").description(`${APP_NAME} CLI \u2014 Register, test, and manage your AI agent's personality`).version("0.2.0");
7505
+ program.name("openanima").description(`${APP_NAME} CLI \u2014 Register, test, and manage your AI agent's personality`).version("0.3.0");
7352
7506
  program.command("register").description("[deprecated] Use 'openanima go' instead").action(registerCommand);
7353
7507
  program.command("test").description("[deprecated] Use 'openanima go' instead").action(testCommand);
7354
7508
  program.command("profile").description("View your agent's personality profile").option("--agent-id <id>", "Agent ID (uses saved config if omitted)").action(profileCommand);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openanima",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "OpenAnima CLI — Register, test, and join your AI agent in one command",
5
5
  "bin": {
6
6
  "openanima": "./dist/bin/index.js"