coherence-cli 0.8.3 → 0.9.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/lib/identity.mjs CHANGED
@@ -1,46 +1,102 @@
1
1
  /**
2
2
  * Identity-first onboarding — runs on first use if no contributor_id in config.
3
+ *
4
+ * Interactive: asks for name + primary identity (e.g. github:seeker71)
5
+ * Non-interactive: auto-generates from COHERENCE_CONTRIBUTOR env, git config,
6
+ * or hostname — then registers with the network.
3
7
  */
4
8
 
5
9
  import { createInterface } from "node:readline/promises";
6
10
  import { stdin, stdout } from "node:process";
11
+ import { execSync } from "node:child_process";
12
+ import { hostname } from "node:os";
13
+ import { createHash } from "node:crypto";
7
14
  import { getContributorId, saveConfig } from "./config.mjs";
8
15
  import { post } from "./api.mjs";
9
16
 
10
- const ONBOARD_PROVIDERS = ["github", "ethereum", "x", "email"];
17
+ const ONBOARD_PROVIDERS = ["github", "ethereum", "x", "discord", "email"];
11
18
 
12
19
  async function prompt(rl, question) {
13
20
  const answer = await rl.question(question);
14
21
  return answer.trim();
15
22
  }
16
23
 
24
+ /**
25
+ * Try to detect identity from environment:
26
+ * 1. COHERENCE_CONTRIBUTOR env var
27
+ * 2. git config user.name (most developers have this)
28
+ * 3. hostname-based hash (last resort)
29
+ */
30
+ function detectIdentity() {
31
+ // 1. Explicit env var
32
+ if (process.env.COHERENCE_CONTRIBUTOR) {
33
+ return { id: process.env.COHERENCE_CONTRIBUTOR, source: "env" };
34
+ }
35
+
36
+ // 2. Git config
37
+ try {
38
+ const gitUser = execSync("git config user.name", { encoding: "utf8", timeout: 3000 }).trim();
39
+ if (gitUser) {
40
+ return { id: gitUser, source: "git" };
41
+ }
42
+ } catch {}
43
+
44
+ // 3. Hostname hash
45
+ const hash = createHash("sha256").update(hostname()).digest("hex").slice(0, 8);
46
+ return { id: `node-${hostname().split(".")[0].toLowerCase()}-${hash}`, source: "hostname" };
47
+ }
48
+
17
49
  /**
18
50
  * Ensure the user has a contributor identity.
19
- * If not, run guided onboarding. Returns the contributor_id.
51
+ * If not, run guided onboarding (interactive) or auto-detect (non-interactive).
20
52
  */
21
53
  export async function ensureIdentity() {
22
54
  let id = getContributorId();
23
55
  if (id) return id;
24
56
 
25
- // Non-interactive environment — can't prompt
57
+ // Non-interactive environment — auto-detect and register silently
26
58
  if (!stdin.isTTY) {
27
- console.error("No contributor identity configured.");
28
- console.error("Set COHERENCE_CONTRIBUTOR or run: cc identity setup");
29
- process.exit(1);
59
+ const detected = detectIdentity();
60
+ saveConfig({ contributor_id: detected.id });
61
+
62
+ // Register with the network
63
+ await post("/api/identity/link", {
64
+ contributor_id: detected.id,
65
+ provider: "name",
66
+ provider_id: detected.id,
67
+ display_name: detected.id,
68
+ });
69
+
70
+ // Try to link git identity too
71
+ try {
72
+ const gitUser = execSync("git config user.name", { encoding: "utf8", timeout: 3000 }).trim();
73
+ const gitEmail = execSync("git config user.email", { encoding: "utf8", timeout: 3000 }).trim();
74
+ if (gitEmail) {
75
+ await post("/api/identity/link", {
76
+ contributor_id: detected.id,
77
+ provider: "email",
78
+ provider_id: gitEmail,
79
+ display_name: gitUser || detected.id,
80
+ });
81
+ }
82
+ } catch {}
83
+
84
+ console.error(`Registered as: ${detected.id} (from ${detected.source})`);
85
+ console.error(`Link identity: cc identity link github <handle>`);
86
+ return detected.id;
30
87
  }
31
88
 
89
+ // Interactive — guided onboarding
32
90
  const rl = createInterface({ input: stdin, output: stdout });
33
91
 
34
92
  console.log();
35
93
  console.log("\x1b[1mWelcome to the Coherence Network.\x1b[0m");
94
+ console.log("Every contribution is traced, scored, and fairly attributed.");
36
95
  console.log();
37
96
 
38
- const name = await prompt(rl, "What's your name? > ");
39
- if (!name) {
40
- console.log("A name is needed to attribute your contributions.");
41
- rl.close();
42
- process.exit(1);
43
- }
97
+ // Suggest detected identity
98
+ const detected = detectIdentity();
99
+ const name = await prompt(rl, `Your name [${detected.id}]: `) || detected.id;
44
100
 
45
101
  saveConfig({ contributor_id: name });
46
102
  id = name;
@@ -53,12 +109,36 @@ export async function ensureIdentity() {
53
109
  display_name: name,
54
110
  });
55
111
 
112
+ console.log();
113
+ console.log("Link an identity to get credit for your work.");
114
+ console.log("Format: provider:handle (e.g. github:seeker71)");
56
115
  console.log();
57
116
 
58
- for (const provider of ONBOARD_PROVIDERS) {
59
- const yn = await prompt(rl, `Link your ${provider}? (y/n) > `);
60
- if (yn.toLowerCase() === "y" || yn.toLowerCase() === "yes") {
61
- const value = await prompt(rl, ` ${provider} handle/address: > `);
117
+ // Ask for primary identity
118
+ const primary = await prompt(rl, "Primary identity (e.g. github:seeker71): ");
119
+ if (primary && primary.includes(":")) {
120
+ const [provider, handle] = primary.split(":", 2);
121
+ if (provider && handle) {
122
+ const result = await post("/api/identity/link", {
123
+ contributor_id: name,
124
+ provider: provider.toLowerCase(),
125
+ provider_id: handle,
126
+ display_name: handle,
127
+ });
128
+ if (result) {
129
+ console.log(` \x1b[32m✓\x1b[0m Linked ${provider}:${handle}`);
130
+ } else {
131
+ console.log(` \x1b[33m!\x1b[0m Could not link. Try later: cc identity link ${provider} ${handle}`);
132
+ }
133
+ }
134
+ }
135
+
136
+ // Offer additional providers
137
+ console.log();
138
+ const more = await prompt(rl, "Link more accounts? (y/n): ");
139
+ if (more.toLowerCase() === "y" || more.toLowerCase() === "yes") {
140
+ for (const provider of ONBOARD_PROVIDERS) {
141
+ const value = await prompt(rl, ` ${provider} handle (enter to skip): `);
62
142
  if (value) {
63
143
  const result = await post("/api/identity/link", {
64
144
  contributor_id: name,
@@ -69,15 +149,16 @@ export async function ensureIdentity() {
69
149
  if (result) {
70
150
  console.log(` \x1b[32m✓\x1b[0m Linked ${provider}:${value}`);
71
151
  } else {
72
- console.log(` \x1b[33m!\x1b[0m Could not link (network issue). Try later: cc identity link ${provider} ${value}`);
152
+ console.log(` \x1b[33m!\x1b[0m Could not link. Try later: cc identity link ${provider} ${value}`);
73
153
  }
74
154
  }
75
155
  }
76
156
  }
77
157
 
78
158
  console.log();
79
- console.log(`Saved to ~/.coherence-network/config.json`);
80
- console.log(`Link more accounts anytime: cc identity link <provider> <id>`);
159
+ console.log(`\x1b[32m✓\x1b[0m Registered as: ${name}`);
160
+ console.log(`Config saved to ~/.coherence-network/config.json`);
161
+ console.log(`Link more anytime: cc identity link <provider> <handle>`);
81
162
  console.log();
82
163
 
83
164
  rl.close();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "coherence-cli",
3
- "version": "0.8.3",
3
+ "version": "0.9.0",
4
4
  "description": "Coherence Network CLI \u2014 trace ideas from inception to payout, with fair attribution, coherence scoring, and 37 identity providers. No signup needed.",
5
5
  "type": "module",
6
6
  "bin": {