@skills-store/rednote 0.1.0 → 0.1.2
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/bin/rednote.js +16 -24
- package/dist/browser/connect-browser.js +172 -0
- package/dist/browser/create-browser.js +52 -0
- package/dist/browser/index.js +35 -0
- package/dist/browser/list-browser.js +50 -0
- package/dist/browser/remove-browser.js +69 -0
- package/{scripts/index.ts → dist/index.js} +19 -25
- package/dist/rednote/checkLogin.js +139 -0
- package/dist/rednote/env.js +69 -0
- package/dist/rednote/getFeedDetail.js +268 -0
- package/dist/rednote/getProfile.js +327 -0
- package/dist/rednote/home.js +210 -0
- package/dist/rednote/index.js +130 -0
- package/dist/rednote/login.js +109 -0
- package/dist/rednote/output-format.js +116 -0
- package/dist/rednote/publish.js +376 -0
- package/dist/rednote/search.js +207 -0
- package/dist/rednote/status.js +201 -0
- package/dist/utils/browser-cli.js +155 -0
- package/dist/utils/browser-core.js +705 -0
- package/package.json +7 -4
- package/scripts/browser/connect-browser.ts +0 -218
- package/scripts/browser/create-browser.ts +0 -81
- package/scripts/browser/index.ts +0 -49
- package/scripts/browser/list-browser.ts +0 -74
- package/scripts/browser/remove-browser.ts +0 -109
- package/scripts/rednote/checkLogin.ts +0 -171
- package/scripts/rednote/env.ts +0 -79
- package/scripts/rednote/getFeedDetail.ts +0 -351
- package/scripts/rednote/getProfile.ts +0 -420
- package/scripts/rednote/home.ts +0 -316
- package/scripts/rednote/index.ts +0 -122
- package/scripts/rednote/login.ts +0 -142
- package/scripts/rednote/output-format.ts +0 -156
- package/scripts/rednote/post-types.ts +0 -51
- package/scripts/rednote/search.ts +0 -316
- package/scripts/rednote/status.ts +0 -280
- package/scripts/utils/browser-cli.ts +0 -176
- package/scripts/utils/browser-core.ts +0 -906
- package/tsconfig.json +0 -13
- /package/{scripts/rednote/collect.ts → dist/rednote/collect.js} +0 -0
- /package/{scripts/rednote/publish.ts → dist/rednote/post-types.js} +0 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { parseArgs } from 'node:util';
|
|
3
|
+
import { findSpec, inspectBrowserInstance, isDefaultInstanceName, isLastConnectMatch, readInstanceStore } from '../utils/browser-core.js';
|
|
4
|
+
import { debugLog, printJson, runCli, stringifyError } from '../utils/browser-cli.js';
|
|
5
|
+
let rednoteAccountStatusProvider = async ()=>({
|
|
6
|
+
loginStatus: 'unknown',
|
|
7
|
+
lastLoginAt: null
|
|
8
|
+
});
|
|
9
|
+
export function registerRednoteAccountStatusProvider(provider) {
|
|
10
|
+
rednoteAccountStatusProvider = provider;
|
|
11
|
+
}
|
|
12
|
+
export async function getRednoteAccountStatus(context) {
|
|
13
|
+
return await rednoteAccountStatusProvider(context);
|
|
14
|
+
}
|
|
15
|
+
function printStatusHelp() {
|
|
16
|
+
process.stdout.write(`rednote status
|
|
17
|
+
|
|
18
|
+
Usage:
|
|
19
|
+
npx -y @skills-store/rednote status [--instance NAME]
|
|
20
|
+
node --experimental-strip-types ./scripts/rednote/status.ts [--instance NAME]
|
|
21
|
+
bun ./scripts/rednote/status.ts [--instance NAME]
|
|
22
|
+
|
|
23
|
+
Options:
|
|
24
|
+
--instance NAME Show status for a custom instance or default browser instance
|
|
25
|
+
-h, --help Show this help
|
|
26
|
+
`);
|
|
27
|
+
}
|
|
28
|
+
function toInstanceState(instance) {
|
|
29
|
+
if (instance.staleLock) {
|
|
30
|
+
return 'stale-lock';
|
|
31
|
+
}
|
|
32
|
+
if (instance.inUse) {
|
|
33
|
+
return 'running';
|
|
34
|
+
}
|
|
35
|
+
if (instance.exists) {
|
|
36
|
+
return 'stopped';
|
|
37
|
+
}
|
|
38
|
+
return 'missing';
|
|
39
|
+
}
|
|
40
|
+
function fromPersistedInstance(instance, source) {
|
|
41
|
+
const store = readInstanceStore();
|
|
42
|
+
return {
|
|
43
|
+
scope: 'custom',
|
|
44
|
+
instanceName: instance.name,
|
|
45
|
+
browser: instance.browser,
|
|
46
|
+
userDataDir: instance.userDataDir,
|
|
47
|
+
createdAt: instance.createdAt,
|
|
48
|
+
lastConnect: isLastConnectMatch(store.lastConnect, 'custom', instance.name, instance.browser),
|
|
49
|
+
source
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
export function resolveStatusTarget(instanceName) {
|
|
53
|
+
const store = readInstanceStore();
|
|
54
|
+
if (instanceName) {
|
|
55
|
+
const normalizedName = instanceName.trim();
|
|
56
|
+
if (!normalizedName) {
|
|
57
|
+
throw new Error('Instance name cannot be empty');
|
|
58
|
+
}
|
|
59
|
+
if (isDefaultInstanceName(normalizedName)) {
|
|
60
|
+
const browser = normalizedName;
|
|
61
|
+
return {
|
|
62
|
+
scope: 'default',
|
|
63
|
+
instanceName: browser,
|
|
64
|
+
browser,
|
|
65
|
+
userDataDir: null,
|
|
66
|
+
createdAt: null,
|
|
67
|
+
lastConnect: isLastConnectMatch(store.lastConnect, 'default', browser, browser),
|
|
68
|
+
source: 'argument'
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
const persisted = store.instances.find((item)=>item.name === normalizedName);
|
|
72
|
+
if (!persisted) {
|
|
73
|
+
throw new Error(`Unknown instance: ${normalizedName}`);
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
scope: 'custom',
|
|
77
|
+
instanceName: persisted.name,
|
|
78
|
+
browser: persisted.browser,
|
|
79
|
+
userDataDir: persisted.userDataDir,
|
|
80
|
+
createdAt: persisted.createdAt,
|
|
81
|
+
lastConnect: isLastConnectMatch(store.lastConnect, 'custom', persisted.name, persisted.browser),
|
|
82
|
+
source: 'argument'
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
if (store.lastConnect) {
|
|
86
|
+
if (store.lastConnect.scope === 'default') {
|
|
87
|
+
return {
|
|
88
|
+
scope: 'default',
|
|
89
|
+
instanceName: store.lastConnect.name,
|
|
90
|
+
browser: store.lastConnect.browser,
|
|
91
|
+
userDataDir: null,
|
|
92
|
+
createdAt: null,
|
|
93
|
+
lastConnect: true,
|
|
94
|
+
source: 'last-connect'
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
const persisted = store.instances.find((item)=>item.name === store.lastConnect?.name);
|
|
98
|
+
if (persisted) {
|
|
99
|
+
return {
|
|
100
|
+
scope: 'custom',
|
|
101
|
+
instanceName: persisted.name,
|
|
102
|
+
browser: persisted.browser,
|
|
103
|
+
userDataDir: persisted.userDataDir,
|
|
104
|
+
createdAt: persisted.createdAt,
|
|
105
|
+
lastConnect: true,
|
|
106
|
+
source: 'last-connect'
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (store.instances.length === 1) {
|
|
111
|
+
return fromPersistedInstance(store.instances[0], 'single-instance');
|
|
112
|
+
}
|
|
113
|
+
throw new Error('No current instance found. Use --instance NAME or connect an instance first.');
|
|
114
|
+
}
|
|
115
|
+
export async function getRednoteStatus(target) {
|
|
116
|
+
debugLog('status', 'get status start', {
|
|
117
|
+
target
|
|
118
|
+
});
|
|
119
|
+
const spec = findSpec(target.browser);
|
|
120
|
+
const inspected = await inspectBrowserInstance(spec, undefined, target.scope === 'custom' ? target.userDataDir ?? undefined : undefined);
|
|
121
|
+
debugLog('status', 'instance inspected', {
|
|
122
|
+
inspected
|
|
123
|
+
});
|
|
124
|
+
let rednote = await getRednoteAccountStatus(target);
|
|
125
|
+
debugLog('status', 'account status provider result', {
|
|
126
|
+
rednote
|
|
127
|
+
});
|
|
128
|
+
if (rednote.loginStatus === 'unknown') {
|
|
129
|
+
try {
|
|
130
|
+
debugLog('status', 'login status unknown, fallback to checkRednoteLogin', {
|
|
131
|
+
target
|
|
132
|
+
});
|
|
133
|
+
const { checkRednoteLogin } = await import('./checkLogin.js');
|
|
134
|
+
const checked = await checkRednoteLogin(target);
|
|
135
|
+
debugLog('status', 'fallback checkRednoteLogin succeeded', {
|
|
136
|
+
checked
|
|
137
|
+
});
|
|
138
|
+
rednote = {
|
|
139
|
+
loginStatus: checked.loginStatus,
|
|
140
|
+
lastLoginAt: checked.lastLoginAt
|
|
141
|
+
};
|
|
142
|
+
} catch (error) {
|
|
143
|
+
debugLog('status', 'fallback checkRednoteLogin failed', {
|
|
144
|
+
error: stringifyError(error)
|
|
145
|
+
});
|
|
146
|
+
rednote = {
|
|
147
|
+
loginStatus: 'unknown',
|
|
148
|
+
lastLoginAt: null
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return {
|
|
153
|
+
ok: true,
|
|
154
|
+
instance: {
|
|
155
|
+
scope: target.scope,
|
|
156
|
+
name: target.instanceName,
|
|
157
|
+
browser: target.browser,
|
|
158
|
+
source: target.source,
|
|
159
|
+
status: toInstanceState(inspected),
|
|
160
|
+
exists: inspected.exists,
|
|
161
|
+
inUse: inspected.inUse,
|
|
162
|
+
pid: inspected.pid,
|
|
163
|
+
remotePort: inspected.remotePort,
|
|
164
|
+
userDataDir: inspected.userDataDir,
|
|
165
|
+
createdAt: target.createdAt,
|
|
166
|
+
lastConnect: target.lastConnect
|
|
167
|
+
},
|
|
168
|
+
rednote
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
export async function runStatusCommand(values = {}) {
|
|
172
|
+
if (values.help) {
|
|
173
|
+
printStatusHelp();
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
const target = resolveStatusTarget(values.instance);
|
|
177
|
+
const result = await getRednoteStatus(target);
|
|
178
|
+
printJson(result);
|
|
179
|
+
}
|
|
180
|
+
async function main() {
|
|
181
|
+
const { values } = parseArgs({
|
|
182
|
+
args: process.argv.slice(2),
|
|
183
|
+
allowPositionals: true,
|
|
184
|
+
strict: false,
|
|
185
|
+
options: {
|
|
186
|
+
instance: {
|
|
187
|
+
type: 'string'
|
|
188
|
+
},
|
|
189
|
+
help: {
|
|
190
|
+
type: 'boolean',
|
|
191
|
+
short: 'h'
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
if (values.help) {
|
|
196
|
+
printStatusHelp();
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
await runStatusCommand(values);
|
|
200
|
+
}
|
|
201
|
+
runCli(import.meta.url, main);
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { parseArgs } from 'node:util';
|
|
3
|
+
import { pathToFileURL } from 'node:url';
|
|
4
|
+
function printHelp(helpText) {
|
|
5
|
+
process.stdout.write(helpText);
|
|
6
|
+
}
|
|
7
|
+
export function parseBrowserCliArgs(argv) {
|
|
8
|
+
const { values, positionals } = parseArgs({
|
|
9
|
+
args: argv,
|
|
10
|
+
allowPositionals: true,
|
|
11
|
+
strict: false,
|
|
12
|
+
options: {
|
|
13
|
+
browser: {
|
|
14
|
+
type: 'string'
|
|
15
|
+
},
|
|
16
|
+
instance: {
|
|
17
|
+
type: 'string'
|
|
18
|
+
},
|
|
19
|
+
name: {
|
|
20
|
+
type: 'string'
|
|
21
|
+
},
|
|
22
|
+
'executable-path': {
|
|
23
|
+
type: 'string'
|
|
24
|
+
},
|
|
25
|
+
'user-data-dir': {
|
|
26
|
+
type: 'string'
|
|
27
|
+
},
|
|
28
|
+
force: {
|
|
29
|
+
type: 'boolean'
|
|
30
|
+
},
|
|
31
|
+
port: {
|
|
32
|
+
type: 'string'
|
|
33
|
+
},
|
|
34
|
+
timeout: {
|
|
35
|
+
type: 'string'
|
|
36
|
+
},
|
|
37
|
+
'kill-timeout': {
|
|
38
|
+
type: 'string'
|
|
39
|
+
},
|
|
40
|
+
'startup-url': {
|
|
41
|
+
type: 'string'
|
|
42
|
+
},
|
|
43
|
+
help: {
|
|
44
|
+
type: 'boolean',
|
|
45
|
+
short: 'h'
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
return {
|
|
50
|
+
values: values,
|
|
51
|
+
positionals
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
export function printJson(value) {
|
|
55
|
+
process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
|
|
56
|
+
}
|
|
57
|
+
export function printInitBrowserHelp() {
|
|
58
|
+
printHelp(`rednote browser
|
|
59
|
+
|
|
60
|
+
Commands:
|
|
61
|
+
list
|
|
62
|
+
create --name NAME [--browser chrome|edge|chromium|brave] [--port 9222]
|
|
63
|
+
remove --name NAME [--force]
|
|
64
|
+
connect [--instance NAME] [--browser chrome|edge|chromium|brave] [--user-data-dir PATH] [--force] [--port 9222]
|
|
65
|
+
|
|
66
|
+
Examples:
|
|
67
|
+
npx -y @skills-store/rednote browser list
|
|
68
|
+
npx -y @skills-store/rednote browser create --name seller-main --browser chrome --port 9222
|
|
69
|
+
npx -y @skills-store/rednote browser remove --name seller-main
|
|
70
|
+
npx -y @skills-store/rednote browser connect --instance seller-main
|
|
71
|
+
npx -y @skills-store/rednote browser connect --browser edge --user-data-dir /tmp/edge-profile --port 9223
|
|
72
|
+
`);
|
|
73
|
+
}
|
|
74
|
+
export function printCreateBrowserHelp() {
|
|
75
|
+
printHelp(`rednote browser create
|
|
76
|
+
|
|
77
|
+
Usage:
|
|
78
|
+
npx -y @skills-store/rednote browser create --name NAME [--browser chrome|edge|chromium|brave] [--port 9222]
|
|
79
|
+
bun ./scripts/browser/create-browser.ts --name NAME [--browser chrome|edge|chromium|brave] [--port 9222]
|
|
80
|
+
`);
|
|
81
|
+
}
|
|
82
|
+
export function printListBrowserHelp() {
|
|
83
|
+
printHelp(`rednote browser list
|
|
84
|
+
|
|
85
|
+
Usage:
|
|
86
|
+
npx -y @skills-store/rednote browser list
|
|
87
|
+
bun ./scripts/browser/list-browser.ts
|
|
88
|
+
`);
|
|
89
|
+
}
|
|
90
|
+
export function printRemoveBrowserHelp() {
|
|
91
|
+
printHelp(`rednote browser remove
|
|
92
|
+
|
|
93
|
+
Usage:
|
|
94
|
+
npx -y @skills-store/rednote browser remove --name NAME [--force]
|
|
95
|
+
bun ./scripts/browser/remove-browser.ts --name NAME [--force]
|
|
96
|
+
`);
|
|
97
|
+
}
|
|
98
|
+
export function printConnectBrowserHelp() {
|
|
99
|
+
printHelp(`rednote browser connect
|
|
100
|
+
|
|
101
|
+
Usage:
|
|
102
|
+
npx -y @skills-store/rednote browser connect [--instance NAME] [--browser chrome|edge|chromium|brave] [--user-data-dir PATH] [--force] [--port 9222]
|
|
103
|
+
bun ./scripts/browser/connect-browser.ts [--instance NAME] [--browser chrome|edge|chromium|brave] [--user-data-dir PATH] [--force] [--port 9222]
|
|
104
|
+
|
|
105
|
+
Notes:
|
|
106
|
+
When using --instance without --port, the stored instance port from data.json is used.
|
|
107
|
+
If no stored port exists yet, a random free port is assigned and saved for next time.
|
|
108
|
+
`);
|
|
109
|
+
}
|
|
110
|
+
export function stringifyError(error) {
|
|
111
|
+
if (error instanceof Error) {
|
|
112
|
+
return error.message;
|
|
113
|
+
}
|
|
114
|
+
return String(error);
|
|
115
|
+
}
|
|
116
|
+
export function isDebugEnabled() {
|
|
117
|
+
const value = process.env.REDNOTE_DEBUG?.trim().toLowerCase();
|
|
118
|
+
return value === '1' || value === 'true' || value === 'yes' || value === 'on';
|
|
119
|
+
}
|
|
120
|
+
export function debugLog(scope, message, payload) {
|
|
121
|
+
if (!isDebugEnabled()) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
const time = new Date().toISOString();
|
|
125
|
+
const suffix = payload ? ` ${JSON.stringify(payload)}` : '';
|
|
126
|
+
process.stderr.write(`[rednote-debug][${time}][${scope}] ${message}${suffix}
|
|
127
|
+
`);
|
|
128
|
+
}
|
|
129
|
+
export function isMainModule(metaUrl) {
|
|
130
|
+
const entryArg = process.argv[1];
|
|
131
|
+
if (!entryArg) {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
return metaUrl === pathToFileURL(path.resolve(entryArg)).href;
|
|
135
|
+
}
|
|
136
|
+
async function finalizeCliProcess(exitCode) {
|
|
137
|
+
await new Promise((resolve)=>process.stdout.write('', ()=>resolve()));
|
|
138
|
+
await new Promise((resolve)=>process.stderr.write('', ()=>resolve()));
|
|
139
|
+
process.exit(exitCode);
|
|
140
|
+
}
|
|
141
|
+
export function runCli(metaUrl, main) {
|
|
142
|
+
if (!isMainModule(metaUrl)) {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
main().then(async ()=>{
|
|
146
|
+
await finalizeCliProcess(0);
|
|
147
|
+
}).catch(async (error)=>{
|
|
148
|
+
process.stderr.write(`${JSON.stringify({
|
|
149
|
+
ok: false,
|
|
150
|
+
error: stringifyError(error)
|
|
151
|
+
}, null, 2)}
|
|
152
|
+
`);
|
|
153
|
+
await finalizeCliProcess(1);
|
|
154
|
+
});
|
|
155
|
+
}
|