@helpfeel/cosense-cli 1.10.1 → 1.11.1
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/package.json +5 -5
- package/src/cli.ts +10 -0
- package/src/commands/replaceLinks.ts +59 -0
- package/src/commands/submitEdit.ts +22 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@helpfeel/cosense-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.11.1",
|
|
4
4
|
"description": "Cosense (旧Scrapbox) のページを読み・調べ・編集するAgent Skill用のCLI",
|
|
5
5
|
"homepage": "https://github.com/helpfeel/cosense-cli",
|
|
6
6
|
"license": "MIT",
|
|
@@ -24,14 +24,14 @@
|
|
|
24
24
|
"format": "oxfmt"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"tsx": "4.23.
|
|
27
|
+
"tsx": "4.23.10"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"@types/node": "24.13.3",
|
|
31
31
|
"npm-run-all": "4.1.5",
|
|
32
|
-
"oxfmt": "0.
|
|
33
|
-
"oxlint": "1.
|
|
34
|
-
"typescript": "
|
|
32
|
+
"oxfmt": "0.61.0",
|
|
33
|
+
"oxlint": "1.76.0",
|
|
34
|
+
"typescript": "7.0.2"
|
|
35
35
|
},
|
|
36
36
|
"engines": {
|
|
37
37
|
"node": ">=24"
|
package/src/cli.ts
CHANGED
|
@@ -63,6 +63,11 @@ import {
|
|
|
63
63
|
readProjectMembersHelp,
|
|
64
64
|
readProjectMembersSummary
|
|
65
65
|
} from './commands/readProjectMembers.ts';
|
|
66
|
+
import {
|
|
67
|
+
replaceLinks,
|
|
68
|
+
replaceLinksHelp,
|
|
69
|
+
replaceLinksSummary
|
|
70
|
+
} from './commands/replaceLinks.ts';
|
|
66
71
|
import {
|
|
67
72
|
submitEdit,
|
|
68
73
|
submitEditHelp,
|
|
@@ -188,6 +193,11 @@ const commands: Record<string, CommandSpec> = {
|
|
|
188
193
|
handler: submitEdit,
|
|
189
194
|
summary: submitEditSummary,
|
|
190
195
|
help: submitEditHelp
|
|
196
|
+
},
|
|
197
|
+
replaceLinks: {
|
|
198
|
+
handler: replaceLinks,
|
|
199
|
+
summary: replaceLinksSummary,
|
|
200
|
+
help: replaceLinksHelp
|
|
191
201
|
}
|
|
192
202
|
};
|
|
193
203
|
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { parseProjectUrlStrict } from '../lib/parseUrl.ts';
|
|
2
|
+
import { requestJson } from '../lib/request.ts';
|
|
3
|
+
import { resolveCredential } from '../lib/settings.ts';
|
|
4
|
+
|
|
5
|
+
export const replaceLinksSummary =
|
|
6
|
+
'旧タイトルへのリンク記法を新しいタイトルに一括置換する';
|
|
7
|
+
|
|
8
|
+
export const replaceLinksHelp = `replaceLinks - 旧タイトルへのリンク記法を新しいタイトルに一括置換する
|
|
9
|
+
|
|
10
|
+
Usage:
|
|
11
|
+
cosense replaceLinks <projectUrl> <oldTitle> <newTitle>
|
|
12
|
+
|
|
13
|
+
引数:
|
|
14
|
+
<projectUrl> プロジェクトのURL (例: https://scrapbox.io/shokai)。 末尾に余分なpathがあるとerror
|
|
15
|
+
<oldTitle> 置換前のページタイトル
|
|
16
|
+
<newTitle> 置換後のページタイトル
|
|
17
|
+
|
|
18
|
+
project内のページを走査し、 <oldTitle> を指すリンク記法 \`[title]\`・hashtag \`#title\`・
|
|
19
|
+
アイコン記法 \`[title.icon]\` を <newTitle> に書き換える。 タイトルの一致は大文字小文字と
|
|
20
|
+
空白/アンダースコアの違いを無視する。 他projectを指す \`[/project/title]\` は対象外。
|
|
21
|
+
リンク記法になっていない平文、 タイトル行、 code block、 CLI記法、 Helpfeel記法の行は書き換えない。
|
|
22
|
+
|
|
23
|
+
ページ自体のタイトルは変わらない。 タイトルの変更は previewEdit / submitEdit で行う。
|
|
24
|
+
|
|
25
|
+
戻り値(plain text):
|
|
26
|
+
更新したページ数を伝えるmessage (例: "3 pages have been successfully updated!")
|
|
27
|
+
|
|
28
|
+
HTTPエラー:
|
|
29
|
+
HTTP 400 <oldTitle> と <newTitle> が同じ / どちらかが空 / <newTitle> がリンク記法として成立しない
|
|
30
|
+
HTTP 401 認証なし
|
|
31
|
+
HTTP 403 権限不足(PAT利用時、projectのmemberでない 等)
|
|
32
|
+
HTTP 500 一部のページの更新に失敗した。 同じ引数で再実行できる。 置換済みのリンクが
|
|
33
|
+
別の文字列へ再置換される事はない
|
|
34
|
+
`;
|
|
35
|
+
|
|
36
|
+
interface ReplaceLinksResponse {
|
|
37
|
+
message: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export const replaceLinks = async (args: string[]): Promise<void> => {
|
|
41
|
+
if (args.length !== 3) {
|
|
42
|
+
throw new Error(
|
|
43
|
+
'Usage: cosense replaceLinks <projectUrl> <oldTitle> <newTitle>'
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
const [projectUrl, oldTitle, newTitle] = args as [string, string, string];
|
|
47
|
+
|
|
48
|
+
const { origin, projectName } = parseProjectUrlStrict(projectUrl);
|
|
49
|
+
const apiUrl = `${origin}/api/pages/${projectName}/replace/links`;
|
|
50
|
+
// projectに紐づくService Accountがあればそれを、無ければPATを使う(読み取りと同じ)
|
|
51
|
+
const credential = resolveCredential(origin, projectName);
|
|
52
|
+
const response = (await requestJson(apiUrl, {
|
|
53
|
+
credential,
|
|
54
|
+
method: 'POST',
|
|
55
|
+
body: { from: oldTitle, to: newTitle }
|
|
56
|
+
})) as ReplaceLinksResponse;
|
|
57
|
+
|
|
58
|
+
process.stdout.write(`${response.message}\n`);
|
|
59
|
+
};
|
|
@@ -20,8 +20,13 @@ Usage:
|
|
|
20
20
|
title: <実際に書き込まれたpage title>
|
|
21
21
|
url: <作成または更新された page の URL>
|
|
22
22
|
|
|
23
|
-
url はサーバーが返す title から再構築される。
|
|
24
|
-
|
|
23
|
+
url はサーバーが返す title から再構築される。 同名ページが既に存在する場合、 サーバーは
|
|
24
|
+
タイトルに auto-suffix を付ける (新規作成でも既存ページのタイトル変更でも起きる)。
|
|
25
|
+
title/url にはその suffix が反映される。
|
|
26
|
+
|
|
27
|
+
既存ページのタイトルが変わった編集では、続けて以下を出力する:
|
|
28
|
+
titleChanged: "<変更前title>" -> "<変更後title>"
|
|
29
|
+
新旧タイトルはそれぞれJSON string
|
|
25
30
|
|
|
26
31
|
HTTPエラー:
|
|
27
32
|
HTTP 400 preview を生成した時と違う project の URL を渡している
|
|
@@ -40,6 +45,7 @@ previewId は1回限り (consume-on-submit)。submit 後・5分 expire 後・con
|
|
|
40
45
|
interface SubmitResponse {
|
|
41
46
|
commitId: string;
|
|
42
47
|
page: { title?: string } | null;
|
|
48
|
+
titleChanged?: { from?: string; to?: string };
|
|
43
49
|
}
|
|
44
50
|
|
|
45
51
|
export const submitEdit = async (args: string[]): Promise<void> => {
|
|
@@ -68,4 +74,18 @@ export const submitEdit = async (args: string[]): Promise<void> => {
|
|
|
68
74
|
process.stdout.write(
|
|
69
75
|
`commitId: ${response.commitId}\ntitle: ${title}\nurl: ${url}\n`
|
|
70
76
|
);
|
|
77
|
+
|
|
78
|
+
// titleChangedはサーバーが対応している場合のみ返る
|
|
79
|
+
const titleChanged = response.titleChanged;
|
|
80
|
+
if (
|
|
81
|
+
typeof titleChanged?.from === 'string' &&
|
|
82
|
+
typeof titleChanged.to === 'string'
|
|
83
|
+
) {
|
|
84
|
+
// タイトルには " や -> が含まれうるので、境界が一意に読めるようJSON stringで出力する
|
|
85
|
+
process.stdout.write(
|
|
86
|
+
`titleChanged: ${JSON.stringify(titleChanged.from)} -> ${JSON.stringify(
|
|
87
|
+
titleChanged.to
|
|
88
|
+
)}\n`
|
|
89
|
+
);
|
|
90
|
+
}
|
|
71
91
|
};
|