bookmark-research 0.5.0-beta.19 → 0.5.0-beta.20
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/.agents/plugins/marketplace.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/package.json +1 -1
- package/scripts/install.py +10 -2
- package/src/onboarding.py +101 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bookmark-research",
|
|
3
|
-
"version": "0.5.0-beta.
|
|
3
|
+
"version": "0.5.0-beta.20",
|
|
4
4
|
"description": "Check bookmark URLs or Canvas packages, compare sources with host-led research, and retain verifiable reports.",
|
|
5
5
|
"license": "GPL-3.0-only",
|
|
6
6
|
"repository": {
|
package/scripts/install.py
CHANGED
|
@@ -583,8 +583,16 @@ def _run_target(args, target, language):
|
|
|
583
583
|
|
|
584
584
|
|
|
585
585
|
def _run_setup(args, installed, host, language, guided):
|
|
586
|
+
from settings import Settings
|
|
587
|
+
existing_config = Settings().path.is_file()
|
|
588
|
+
interactive = guided and (getattr(args, "interaction", "auto") == "always" or not existing_config)
|
|
589
|
+
if guided and existing_config and getattr(args, "interaction", "auto") != "always":
|
|
590
|
+
print(_message(language,
|
|
591
|
+
"Retained existing configuration (%s). Run `bookmark-research setup` to modify preferences or keys." % Settings().path,
|
|
592
|
+
"✓ 沿用已有研究偏好与密钥配置(%s);如需修改请运行 bookmark-research setup。" % Settings().path),
|
|
593
|
+
file=sys.stderr)
|
|
586
594
|
command = [sys.executable, "-B", str(installed / "src/cli.py"), "setup", "--lang", language,
|
|
587
|
-
"--host", _setup_host(host), "--interactive" if
|
|
595
|
+
"--host", _setup_host(host), "--interactive" if interactive else "--non-interactive"]
|
|
588
596
|
if args.preferences:
|
|
589
597
|
command.extend(["--input", args.preferences])
|
|
590
598
|
if args.skip_checks:
|
|
@@ -592,7 +600,7 @@ def _run_setup(args, installed, host, language, guided):
|
|
|
592
600
|
if args.test_retrieval:
|
|
593
601
|
command.append("--test-retrieval")
|
|
594
602
|
if not (installed / "src/onboarding.py").is_file():
|
|
595
|
-
requested =
|
|
603
|
+
requested = interactive or bool(args.preferences) or args.test_retrieval
|
|
596
604
|
return {"completed": False if requested else None, "status": "unsupported",
|
|
597
605
|
"message": "The installed version predates guided setup; install a newer version to use setup."}
|
|
598
606
|
# The installed version owns its settings schema. Do not use the
|
package/src/onboarding.py
CHANGED
|
@@ -108,7 +108,7 @@ class Console(Prompter):
|
|
|
108
108
|
with reader, writer:
|
|
109
109
|
yield cls(reader, writer, language)
|
|
110
110
|
|
|
111
|
-
def install_targets(self, args):
|
|
111
|
+
def install_targets(self, args, existing_targets=None):
|
|
112
112
|
self.intro("Bookmark Research — guided installation", "Bookmark Research — 引导安装")
|
|
113
113
|
requested = args.host
|
|
114
114
|
if isinstance(requested, str):
|
|
@@ -119,6 +119,104 @@ class Console(Prompter):
|
|
|
119
119
|
client = resolve_dsh(getattr(args, "dsh", None))
|
|
120
120
|
if client["source"] == "desktop":
|
|
121
121
|
args.dsh = client["binary"]
|
|
122
|
+
if existing_targets is None and not requested:
|
|
123
|
+
try:
|
|
124
|
+
scripts_dir = Path(__file__).resolve().parents[1] / "scripts"
|
|
125
|
+
if str(scripts_dir) not in sys.path:
|
|
126
|
+
sys.path.insert(0, str(scripts_dir))
|
|
127
|
+
from launcher import installed_targets
|
|
128
|
+
existing_targets = installed_targets(codex=getattr(args, "codex", "codex"))
|
|
129
|
+
except Exception:
|
|
130
|
+
existing_targets = []
|
|
131
|
+
if existing_targets and not requested:
|
|
132
|
+
target_version = None
|
|
133
|
+
try:
|
|
134
|
+
from export_bundle import read_plugin_manifest
|
|
135
|
+
target_version = read_plugin_manifest(Path(__file__).resolve().parents[1]).get("version")
|
|
136
|
+
except Exception:
|
|
137
|
+
pass
|
|
138
|
+
desc_lines = []
|
|
139
|
+
upgrade_options = []
|
|
140
|
+
for idx, row in enumerate(existing_targets):
|
|
141
|
+
h_name = row.get("host")
|
|
142
|
+
label = next((en for name, en, _ in HOSTS if name == h_name), h_name)
|
|
143
|
+
zh_label = next((zh for name, _, zh in HOSTS if name == h_name), h_name)
|
|
144
|
+
details = []
|
|
145
|
+
for k in ("scope", "project", "profile"):
|
|
146
|
+
if row.get(k):
|
|
147
|
+
details.append(k + "=" + str(row[k]))
|
|
148
|
+
ver = row.get("version")
|
|
149
|
+
ver_str = (" (v" + ver + ")") if ver else ""
|
|
150
|
+
det_str = (" [" + ", ".join(details) + "]") if details else ""
|
|
151
|
+
desc_lines.append((label + det_str + ver_str, zh_label + det_str + ver_str))
|
|
152
|
+
|
|
153
|
+
if target_version and ver:
|
|
154
|
+
if target_version != ver.split("+")[0]:
|
|
155
|
+
ver_hint_en = "v%s → v%s (upgrade)" % (ver, target_version)
|
|
156
|
+
ver_hint_zh = "当前 v%s → 目标 v%s(升级覆盖)" % (ver, target_version)
|
|
157
|
+
else:
|
|
158
|
+
ver_hint_en = "v%s (latest) · overwrite" % ver
|
|
159
|
+
ver_hint_zh = "当前已是最新 v%s · 覆盖更新" % ver
|
|
160
|
+
elif ver:
|
|
161
|
+
ver_hint_en = "v%s" % ver
|
|
162
|
+
ver_hint_zh = "当前版本 v%s" % ver
|
|
163
|
+
else:
|
|
164
|
+
ver_hint_en = "installed"
|
|
165
|
+
ver_hint_zh = "已安装"
|
|
166
|
+
upgrade_options.append(Option(
|
|
167
|
+
str(idx),
|
|
168
|
+
label + det_str,
|
|
169
|
+
zh_label + det_str,
|
|
170
|
+
ver_hint_en,
|
|
171
|
+
ver_hint_zh,
|
|
172
|
+
hint_always=True
|
|
173
|
+
))
|
|
174
|
+
|
|
175
|
+
self.note("Detected existing installations", "检测到已安装宿主", desc_lines)
|
|
176
|
+
host_summary = ", ".join(row.get("host") for row in existing_targets)
|
|
177
|
+
mode = self.select("Installation mode", "请选择操作", [
|
|
178
|
+
Option("upgrade",
|
|
179
|
+
"Upgrade / overwrite installed hosts (%d detected: %s)" % (len(existing_targets), host_summary),
|
|
180
|
+
"升级覆盖已安装宿主(检测到 %d 个:%s)" % (len(existing_targets), host_summary),
|
|
181
|
+
"select which hosts to upgrade, defaults to all",
|
|
182
|
+
"回车默认全选升级,也可自选指定宿主",
|
|
183
|
+
hint_always=True),
|
|
184
|
+
Option("custom",
|
|
185
|
+
"Re-select hosts and customize options from scratch",
|
|
186
|
+
"重新选择宿主与自定义配置",
|
|
187
|
+
"choose hosts and options from scratch",
|
|
188
|
+
"从头重新勾选宿主与参数")
|
|
189
|
+
], "upgrade")
|
|
190
|
+
if mode == "upgrade":
|
|
191
|
+
if len(existing_targets) == 1:
|
|
192
|
+
chosen = ["0"]
|
|
193
|
+
else:
|
|
194
|
+
chosen = self.multiselect(
|
|
195
|
+
"Select installed hosts to upgrade (Space to toggle, Enter to confirm)",
|
|
196
|
+
"选择要升级覆盖的宿主?(空格 勾选/取消,回车 确认)",
|
|
197
|
+
upgrade_options,
|
|
198
|
+
defaults=[str(i) for i in range(len(existing_targets))]
|
|
199
|
+
)
|
|
200
|
+
targets = [{"host": existing_targets[int(i)]["host"],
|
|
201
|
+
"scope": existing_targets[int(i)].get("scope"),
|
|
202
|
+
"project": existing_targets[int(i)].get("project"),
|
|
203
|
+
"profile": existing_targets[int(i)].get("profile")}
|
|
204
|
+
for i in chosen]
|
|
205
|
+
lines = []
|
|
206
|
+
for target in targets:
|
|
207
|
+
label = next((en for name, en, _ in HOSTS if name == target["host"]), target["host"])
|
|
208
|
+
detail = ", ".join(key + "=" + str(target[key]) for key in ("scope", "project", "profile") if target.get(key))
|
|
209
|
+
lines.append((label + (": " + detail if detail else ""), label + (":" + detail if detail else "")))
|
|
210
|
+
self.note("Upgrade plan", "升级覆盖计划", lines)
|
|
211
|
+
if client["source"] == "desktop" and any(target["host"] == "dsh" for target in targets):
|
|
212
|
+
self.note("DeepSeek Harness (dsh) CLI", "DeepSeek Harness (dsh) CLI", [(client["binary"], client["binary"])])
|
|
213
|
+
if not self.confirm("Upgrade now?", "现在升级覆盖?", True):
|
|
214
|
+
if not self.confirm("Re-select hosts and options?", "重新选择宿主与选项?", True):
|
|
215
|
+
raise KeyboardInterrupt
|
|
216
|
+
else:
|
|
217
|
+
first = targets[0]
|
|
218
|
+
args.host, args.scope, args.project, args.profile = first["host"], first.get("scope"), first.get("project"), first.get("profile")
|
|
219
|
+
return targets
|
|
122
220
|
while True:
|
|
123
221
|
if requested:
|
|
124
222
|
hosts = list(dict.fromkeys(requested))
|
|
@@ -131,10 +229,11 @@ class Console(Prompter):
|
|
|
131
229
|
"PATH 中未找到任何受支持的宿主 CLI(codex、claude、dsh)。")
|
|
132
230
|
raise ValueError("No host CLI found; install Codex, Claude Code or DeepSeek Harness (dsh), "
|
|
133
231
|
"or pass --codex/--claude/--dsh PATH to point at its executable")
|
|
232
|
+
preselected = [row["host"] for row in (existing_targets or []) if found.get(row.get("host"))] or [name for name, _, _ in HOSTS if found[name]]
|
|
134
233
|
hosts = self.multiselect("Install into which hosts? (Space to toggle, Enter to confirm)",
|
|
135
234
|
"安装到哪些宿主?(空格 勾选/取消,回车 确认)", [
|
|
136
235
|
Option(name, en, zh, *hints[name], disabled=not found[name]) for name, en, zh in HOSTS],
|
|
137
|
-
|
|
236
|
+
preselected)
|
|
138
237
|
# A carrier that ships its own pnpm is the Desktop CLI, however it was found:
|
|
139
238
|
# only that CLI may manage the profile name Desktop reserves for itself.
|
|
140
239
|
desktop = client["bundled_pnpm"] is not None
|