plotlink-ows 0.1.13 → 0.1.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -6
- package/bin/plotlink-ows.js +19 -72
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
# PlotLink OWS Writer
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/plotlink-ows)
|
|
4
|
+
|
|
3
5
|
**Anyone can become a fiction writer with just an idea.**
|
|
4
6
|
|
|
7
|
+
```bash
|
|
8
|
+
npx plotlink-ows init # one-time setup (~2 minutes)
|
|
9
|
+
npx plotlink-ows # start writing
|
|
10
|
+
```
|
|
11
|
+
|
|
5
12
|
PlotLink OWS Writer is a local AI writing assistant that turns your ideas into published, tokenized fiction stories on [plotlink.xyz](https://plotlink.xyz). You bring the concept — the AI handles the writing, editing, and on-chain publishing. Every story you publish becomes a tradable token on a bonding curve, earning you royalties from every trade.
|
|
6
13
|
|
|
7
14
|
No writing experience needed. No crypto complexity. Just an idea and a conversation with your AI co-writer.
|
|
@@ -100,15 +107,11 @@ PlotLink is currently in live testing on Base mainnet with public launch planned
|
|
|
100
107
|
### Quick Start
|
|
101
108
|
|
|
102
109
|
```bash
|
|
103
|
-
npx plotlink-ows init #
|
|
110
|
+
npx plotlink-ows init # set passphrase + create wallet
|
|
104
111
|
npx plotlink-ows # start app + open browser
|
|
105
112
|
```
|
|
106
113
|
|
|
107
|
-
The setup wizard
|
|
108
|
-
|
|
109
|
-
1. Set a passphrase (encrypts your OWS wallet)
|
|
110
|
-
2. Connect your LLM (Anthropic, OpenAI, Gemini, or local model)
|
|
111
|
-
3. Create your OWS wallet (encrypted on your machine)
|
|
114
|
+
The setup wizard creates your encrypted OWS wallet. Then the Web UI guides you through connecting your LLM (login with Anthropic, OpenAI, or Gemini via OAuth — or use a local model like Ollama).
|
|
112
115
|
|
|
113
116
|
### Commands
|
|
114
117
|
|
package/bin/plotlink-ows.js
CHANGED
|
@@ -55,31 +55,34 @@ function ask(rl, question) {
|
|
|
55
55
|
|
|
56
56
|
function askSecret(question) {
|
|
57
57
|
return new Promise((resolve) => {
|
|
58
|
-
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
59
58
|
process.stdout.write(question);
|
|
60
59
|
const stdin = process.stdin;
|
|
61
60
|
const wasRaw = stdin.isRaw;
|
|
62
61
|
if (stdin.setRawMode) stdin.setRawMode(true);
|
|
62
|
+
stdin.resume();
|
|
63
63
|
let input = "";
|
|
64
64
|
const onData = (ch) => {
|
|
65
65
|
const c = ch.toString();
|
|
66
66
|
if (c === "\n" || c === "\r") {
|
|
67
67
|
if (stdin.setRawMode) stdin.setRawMode(wasRaw);
|
|
68
68
|
stdin.removeListener("data", onData);
|
|
69
|
+
stdin.pause();
|
|
69
70
|
process.stdout.write("\n");
|
|
70
|
-
rl.close();
|
|
71
71
|
resolve(input);
|
|
72
72
|
} else if (c === "\u0003") {
|
|
73
|
+
if (stdin.setRawMode) stdin.setRawMode(wasRaw);
|
|
73
74
|
process.exit(0);
|
|
74
75
|
} else if (c === "\u007F" || c === "\b") {
|
|
75
|
-
input
|
|
76
|
+
if (input.length > 0) {
|
|
77
|
+
input = input.slice(0, -1);
|
|
78
|
+
process.stdout.write("\b \b");
|
|
79
|
+
}
|
|
76
80
|
} else {
|
|
77
81
|
input += c;
|
|
78
82
|
process.stdout.write("*");
|
|
79
83
|
}
|
|
80
84
|
};
|
|
81
85
|
stdin.on("data", onData);
|
|
82
|
-
stdin.resume();
|
|
83
86
|
});
|
|
84
87
|
}
|
|
85
88
|
|
|
@@ -113,8 +116,6 @@ async function cmdInit() {
|
|
|
113
116
|
header("PlotLink OWS — Setup Wizard");
|
|
114
117
|
log("Let's get your local writer app configured.\n");
|
|
115
118
|
|
|
116
|
-
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
117
|
-
|
|
118
119
|
// Step 1: Prerequisites
|
|
119
120
|
header("Step 1: Prerequisites");
|
|
120
121
|
const nodeVersion = process.version;
|
|
@@ -136,60 +137,27 @@ async function cmdInit() {
|
|
|
136
137
|
|
|
137
138
|
// Step 2: Passphrase
|
|
138
139
|
header("Step 2: Passphrase");
|
|
139
|
-
log("
|
|
140
|
-
|
|
141
|
-
|
|
140
|
+
log("This passphrase encrypts your OWS (Open Wallet Standard) wallet.");
|
|
141
|
+
log("Your private key is stored locally and never leaves your machine.");
|
|
142
|
+
log("The passphrase protects signing and app access.\n");
|
|
143
|
+
log("Learn more: https://docs.openwallet.sh/\n");
|
|
144
|
+
const passphrase = await askSecret(" Passphrase (min 8 chars): ");
|
|
145
|
+
const confirm = await askSecret(" Confirm: ");
|
|
142
146
|
|
|
143
147
|
if (passphrase !== confirm) {
|
|
144
148
|
error("Passphrases don't match.");
|
|
145
|
-
rl.close();
|
|
146
149
|
process.exit(1);
|
|
147
150
|
}
|
|
148
151
|
if (passphrase.length < 8) {
|
|
149
152
|
error("Passphrase must be at least 8 characters.");
|
|
150
|
-
rl.close();
|
|
151
153
|
process.exit(1);
|
|
152
154
|
}
|
|
153
155
|
|
|
154
156
|
writeEnvVar("OWS_PASSPHRASE", passphrase);
|
|
155
157
|
success("Passphrase set");
|
|
156
158
|
|
|
157
|
-
// Step 3:
|
|
158
|
-
header("Step 3:
|
|
159
|
-
log("1) Anthropic (recommended)");
|
|
160
|
-
log("2) OpenAI");
|
|
161
|
-
log("3) Google Gemini");
|
|
162
|
-
log("4) Local (Ollama/LM Studio)\n");
|
|
163
|
-
|
|
164
|
-
const choice = await ask(rl, " Choose [1-4]: ");
|
|
165
|
-
const providers = {
|
|
166
|
-
"1": { id: "anthropic", name: "Anthropic", envKey: "ANTHROPIC_API_KEY", model: "claude-sonnet-4-6" },
|
|
167
|
-
"2": { id: "openai", name: "OpenAI", envKey: "OPENAI_API_KEY", model: "gpt-4.1-mini" },
|
|
168
|
-
"3": { id: "gemini", name: "Gemini", envKey: "GEMINI_API_KEY", model: "gemini-2.5-flash" },
|
|
169
|
-
"4": { id: "local", name: "Local", envKey: null, model: "llama3.2" },
|
|
170
|
-
};
|
|
171
|
-
|
|
172
|
-
const provider = providers[choice] || providers["1"];
|
|
173
|
-
let baseUrl = "";
|
|
174
|
-
|
|
175
|
-
if (provider.id === "local") {
|
|
176
|
-
baseUrl = await ask(rl, " Base URL [http://localhost:11434]: ") || "http://localhost:11434";
|
|
177
|
-
const modelName = await ask(rl, ` Model name [${provider.model}]: `) || provider.model;
|
|
178
|
-
provider.model = modelName;
|
|
179
|
-
rl.close();
|
|
180
|
-
} else {
|
|
181
|
-
rl.close();
|
|
182
|
-
const apiKey = await askSecret(` ${provider.name} API key: `);
|
|
183
|
-
if (apiKey) {
|
|
184
|
-
writeEnvVar(provider.envKey, apiKey);
|
|
185
|
-
success(`${provider.name} API key saved`);
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
success(`Provider: ${provider.name} / ${provider.model}`);
|
|
190
|
-
|
|
191
|
-
// Step 4: OWS Wallet
|
|
192
|
-
header("Step 4: OWS Wallet");
|
|
159
|
+
// Step 3: OWS Wallet
|
|
160
|
+
header("Step 3: OWS Wallet");
|
|
193
161
|
try {
|
|
194
162
|
const ows = require("@open-wallet-standard/core");
|
|
195
163
|
const wallets = ows.listWallets();
|
|
@@ -211,45 +179,25 @@ async function cmdInit() {
|
|
|
211
179
|
}
|
|
212
180
|
} catch (err) {
|
|
213
181
|
warn(`Wallet creation skipped: ${err.message}`);
|
|
214
|
-
warn("You can create it later from the app
|
|
182
|
+
warn("You can create it later from the app.");
|
|
215
183
|
}
|
|
216
184
|
|
|
217
185
|
// Save config
|
|
218
186
|
const config = {
|
|
219
187
|
port: 7777,
|
|
220
188
|
passphrase_hash: hashPassphrase(passphrase),
|
|
221
|
-
llm: {
|
|
222
|
-
provider: provider.id,
|
|
223
|
-
model: provider.model,
|
|
224
|
-
...(baseUrl && { baseUrl }),
|
|
225
|
-
},
|
|
226
189
|
wallet_name: "plotlink-writer",
|
|
227
190
|
created_at: new Date().toISOString(),
|
|
228
191
|
};
|
|
229
192
|
writeConfig(config);
|
|
230
193
|
|
|
231
|
-
//
|
|
232
|
-
const agentConfig = {
|
|
233
|
-
llm: {
|
|
234
|
-
activeProvider: provider.id,
|
|
235
|
-
activeModel: provider.model,
|
|
236
|
-
...(provider.id === "local" && {
|
|
237
|
-
local: { baseUrl, model: provider.model, apiType: "ollama" },
|
|
238
|
-
}),
|
|
239
|
-
...(provider.id !== "local" && {
|
|
240
|
-
[provider.id]: { apiKey: `env:${provider.envKey}`, model: provider.model },
|
|
241
|
-
}),
|
|
242
|
-
},
|
|
243
|
-
};
|
|
244
|
-
fs.writeFileSync(AGENT_CONFIG_FILE, JSON.stringify(agentConfig, null, 2) + "\n");
|
|
245
|
-
|
|
246
|
-
// Step 5: Done
|
|
194
|
+
// Step 4: Done
|
|
247
195
|
header("Setup Complete!");
|
|
248
|
-
log(`LLM: ${provider.name} / ${provider.model}`);
|
|
249
196
|
log(`Port: ${config.port}`);
|
|
250
197
|
log(`Config: ${CONFIG_FILE}`);
|
|
251
198
|
log("");
|
|
252
|
-
log('Run \x1b[1mnpx plotlink-ows\x1b[0m to start
|
|
199
|
+
log('Run \x1b[1mnpx plotlink-ows\x1b[0m to start the app.');
|
|
200
|
+
log("You'll connect your LLM (Anthropic, OpenAI, Gemini) via the Web UI.");
|
|
253
201
|
log("");
|
|
254
202
|
|
|
255
203
|
process.exit(0);
|
|
@@ -341,7 +289,6 @@ function cmdStatus() {
|
|
|
341
289
|
}
|
|
342
290
|
|
|
343
291
|
log(`Config: ${CONFIG_FILE}`);
|
|
344
|
-
log(`LLM: ${config.llm?.provider || "—"} / ${config.llm?.model || "—"}`);
|
|
345
292
|
log(`Port: ${config.port || 7777}`);
|
|
346
293
|
|
|
347
294
|
// Wallet
|