@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.
Files changed (42) hide show
  1. package/bin/rednote.js +16 -24
  2. package/dist/browser/connect-browser.js +172 -0
  3. package/dist/browser/create-browser.js +52 -0
  4. package/dist/browser/index.js +35 -0
  5. package/dist/browser/list-browser.js +50 -0
  6. package/dist/browser/remove-browser.js +69 -0
  7. package/{scripts/index.ts → dist/index.js} +19 -25
  8. package/dist/rednote/checkLogin.js +139 -0
  9. package/dist/rednote/env.js +69 -0
  10. package/dist/rednote/getFeedDetail.js +268 -0
  11. package/dist/rednote/getProfile.js +327 -0
  12. package/dist/rednote/home.js +210 -0
  13. package/dist/rednote/index.js +130 -0
  14. package/dist/rednote/login.js +109 -0
  15. package/dist/rednote/output-format.js +116 -0
  16. package/dist/rednote/publish.js +376 -0
  17. package/dist/rednote/search.js +207 -0
  18. package/dist/rednote/status.js +201 -0
  19. package/dist/utils/browser-cli.js +155 -0
  20. package/dist/utils/browser-core.js +705 -0
  21. package/package.json +7 -4
  22. package/scripts/browser/connect-browser.ts +0 -218
  23. package/scripts/browser/create-browser.ts +0 -81
  24. package/scripts/browser/index.ts +0 -49
  25. package/scripts/browser/list-browser.ts +0 -74
  26. package/scripts/browser/remove-browser.ts +0 -109
  27. package/scripts/rednote/checkLogin.ts +0 -171
  28. package/scripts/rednote/env.ts +0 -79
  29. package/scripts/rednote/getFeedDetail.ts +0 -351
  30. package/scripts/rednote/getProfile.ts +0 -420
  31. package/scripts/rednote/home.ts +0 -316
  32. package/scripts/rednote/index.ts +0 -122
  33. package/scripts/rednote/login.ts +0 -142
  34. package/scripts/rednote/output-format.ts +0 -156
  35. package/scripts/rednote/post-types.ts +0 -51
  36. package/scripts/rednote/search.ts +0 -316
  37. package/scripts/rednote/status.ts +0 -280
  38. package/scripts/utils/browser-cli.ts +0 -176
  39. package/scripts/utils/browser-core.ts +0 -906
  40. package/tsconfig.json +0 -13
  41. /package/{scripts/rednote/collect.ts → dist/rednote/collect.js} +0 -0
  42. /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
+ }