ai_co_discuss 0.2.24 → 0.2.25
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/docs/runner.md +1 -1
- package/package.json +1 -1
- package/runner/discussion_adapters.mjs +7 -1
- package/runner/discussion_runner.mjs +4 -4
- package/web/app.js +9 -1
- package/web/modern.css +1 -1
- package/web/modern.js +17 -11
package/docs/runner.md
CHANGED
|
@@ -294,7 +294,7 @@ Codex 要求 CLI 0.163.0 或更新版本,使用 permission profiles 和本地
|
|
|
294
294
|
|
|
295
295
|
2026-10-18 本机实测(本轮权限调整前):Claude 主持、Codex 与 Gemini 专家完成一场最小讨论。Windows 的 Codex / agy 经 PowerShell 调用时优先执行 npm 生成的 `codiscuss.ps1`;Codex elevated 沙箱内即使当前用户为 RemoteSigned 也拒绝 `.ps1`,Codex 自行改用 `cmd.exe` 调用 `codiscuss.cmd` 后成功。`agy` 非交互模式下被拒绝的工具也可能伴随退出码 0,最终仍以网站业务保存为准。`agy` 显式使用 `--print-timeout 0`,由房间的单次执行时限和整场截止控制停止,避免额外的 CLI 默认时限提前截断。
|
|
296
296
|
|
|
297
|
-
结构化失败(Codex `turn.failed`、Antigravity 非 `SUCCESS` 结果)、非零退出码、缺少会话 ID
|
|
297
|
+
结构化失败(Codex `turn.failed`、Antigravity 非 `SUCCESS` 结果)、非零退出码、缺少会话 ID 或成功结束事件均记录为失败;软件已启动后不自动重发。正常退出后若网站尚未保存本次结果,复查后暂停。agy 无人值守时遇到未放行的命令会自动拒绝并直接结束会话;接入程序记录被拒的命令,并写入暂停原因,任务提示也要求 agy 仅用 `run_command` 运行 codiscuss 子命令、浏览项目改用 `list_dir` 等工具。同一参与者兼任主持与专家时,主持保存安排后进程可能仍在退出;该参与者由本服务创建的进程全部退出前不交付下一次执行,避免续接同一会话时出现两个写入者。暂停或停止接入服务会终止本服务创建的 CLI 进程,保留会话绑定和本机日志。
|
|
298
298
|
|
|
299
299
|
2026-10-19 权限调整验证:Windows / Codex CLI 0.163.0 的本地配置检查采用了本次 profile;以原生 `sandbox`(`unelevated`)运行无模型的文件操作,确认项目 cwd 保持、中文文件可读、只读模式拒绝项目与运行目录写入、可写模式允许项目写入但仍拒绝运行目录写入,两种模式均可写草稿并访问本机 HTTP。此证据不覆盖 elevated 模式、其他平台或本轮调整后的真实模型讨论。
|
|
300
300
|
|
package/package.json
CHANGED
|
@@ -380,6 +380,12 @@ function cli_event(adapter, state, event, task) {
|
|
|
380
380
|
return;
|
|
381
381
|
}
|
|
382
382
|
if (event.event === 'init') bind_cli_session(state, event.conversation_id, task);
|
|
383
|
+
const step = event.step_update;
|
|
384
|
+
// Headless agy ends its turn when a command needs approval; remember which one so the pause can name it.
|
|
385
|
+
if (step?.state === 'ERROR' && /permission/.test(step.tool_info?.error?.message || '')) {
|
|
386
|
+
const command = step.tool_info.parameters?.CommandLine || step.tool_name || '';
|
|
387
|
+
state.denial = `运行了未授权的命令「${String(command).slice(0, 120)}」,无人值守模式下无法确认权限而被自动拒绝,随后会话结束`;
|
|
388
|
+
}
|
|
383
389
|
if (event.event === 'result') {
|
|
384
390
|
const result = event.result || {};
|
|
385
391
|
if (result.conversation_id) bind_cli_session(state, result.conversation_id, task);
|
|
@@ -443,7 +449,7 @@ function monitor_cli(child, config, binding, task) {
|
|
|
443
449
|
if (!state.spawned) return;
|
|
444
450
|
const error = cli_exit_error(state, code, signal);
|
|
445
451
|
if (error) task.on_failure(error);
|
|
446
|
-
else task.on_exit?.();
|
|
452
|
+
else task.on_exit?.(state.denial);
|
|
447
453
|
});
|
|
448
454
|
return state;
|
|
449
455
|
}
|
|
@@ -197,7 +197,7 @@ export function task_files(config, event, token, binding) {
|
|
|
197
197
|
project_name: adapter.project_name || null, cwd: adapter.cwd || null, project_access: adapter.project_access,
|
|
198
198
|
draft_directory,
|
|
199
199
|
role: event.role, turn_id: event.turn_id, skills, cli, subcommands: TASK_SUBCOMMANDS, access_file: access_path,
|
|
200
|
-
instructions:
|
|
200
|
+
instructions: `${adapter.adapter === 'antigravity_cli' ? `无人值守下 run_command 只能运行 ${cli} 的 subcommands 子命令,其他命令会被自动拒绝并使会话直接结束;浏览项目用 list_dir、find_by_name、grep_search、view_file。` : ''}读取指定技能;网站命令只用 ${cli} 的 subcommands 子命令,命令以 ${cli} 开头,不用 python discuss.py、cd、管道或其他入口;${auto_enter ? '接入程序已进入本次执行,不要再执行 execution enter。' : `使用 ${cli} execution enter 房间 执行编号 --access-file 凭据路径 进入。进入成功后才处理本次安排;`}凭据文件由 CLI 内部读取,不要打印或读取其 token。每次业务写入都带 --access-file。答案草稿只保存到 draft_directory,不修改任务、凭据、日志或调度数据库;${project_rule}只处理本次工作,不建定时任务。主持创建下一安排或收束即结束,专家提交原文后结束。无效或已进入的任务不要重复执行。` });
|
|
201
201
|
const read_rule = windows_rg() ? '读取含中文的技能或文本文件时用 rg --encoding utf-8 . 文件路径,不用 Get-Content(Windows PowerShell 会按系统编码读出乱码,需要反复重试)。' : '';
|
|
202
202
|
const scope = `本次只放行任务内 subcommands 列出的 ${cli} 子命令,命令以 ${cli} 开头,不用 python discuss.py、cd、管道或其他入口。任务内 cwd 是讨论项目目录;${project_rule}项目读写仍受软件实际权限和议题授权约束。不读取凭据内容。${read_rule}`;
|
|
203
203
|
const plan_rule = event.role === 'host' ? '安排专家回应时先写发言计划,用 turn create --plan-file 一次排满本轮每位专家,不要每次只排一位。' : '';
|
|
@@ -217,7 +217,7 @@ export class DiscussionRunner {
|
|
|
217
217
|
this.store = store;
|
|
218
218
|
this.deliver = deliver;
|
|
219
219
|
this.children = new Set();
|
|
220
|
-
this.exited = new
|
|
220
|
+
this.exited = new Map();
|
|
221
221
|
this.running = new Map();
|
|
222
222
|
this.seen = new Set();
|
|
223
223
|
this.blocked = new Set();
|
|
@@ -262,7 +262,7 @@ export class DiscussionRunner {
|
|
|
262
262
|
on_process: child => this.track(event.participant, child),
|
|
263
263
|
on_output: (path, chunk) => appendFileSync(path, chunk, { mode: 0o600 }),
|
|
264
264
|
on_failure: error => { try { this.store.record(row.id, { error }); } catch { /* Store may already be closed at shutdown. */ } },
|
|
265
|
-
on_exit:
|
|
265
|
+
on_exit: detail => this.exited.set(row.id, detail || ''),
|
|
266
266
|
});
|
|
267
267
|
if (result.session_id) this.store.bind(event.participant, result.session_id);
|
|
268
268
|
this.store.record(row.id, { status: result.status, receipt: result.receipt || '' });
|
|
@@ -311,7 +311,7 @@ export class DiscussionRunner {
|
|
|
311
311
|
if (this.exited.has(row.id) && ['dispatched', 'started'].includes(event.status)) {
|
|
312
312
|
// A business write may have just completed the task; recheck before declaring a silent exit.
|
|
313
313
|
const latest = await api(this.config, `/events/${row.id}`, { action: 'view' });
|
|
314
|
-
if (['dispatched', 'started'].includes(latest.status)) return this.fail(row, `${event.participant}
|
|
314
|
+
if (['dispatched', 'started'].includes(latest.status)) return this.fail(row, `${event.participant} 会话已结束,但未保存本次结果${this.exited.get(row.id) ? `:${this.exited.get(row.id)}` : ''}`);
|
|
315
315
|
return this.reconcile(row, latest);
|
|
316
316
|
}
|
|
317
317
|
if (event.status === 'started' && event.lease_until <= Math.floor(Date.now() / 1000)) return this.fail(row, '执行租约到期;旧会话不能继续写入');
|
package/web/app.js
CHANGED
|
@@ -1607,6 +1607,14 @@ function participant_model(name, room, saved) {
|
|
|
1607
1607
|
return `${model} · ${effort}`;
|
|
1608
1608
|
}
|
|
1609
1609
|
|
|
1610
|
+
/** Label how a member answers: the registered adapter says API / App; other locally woken members are CLI. */
|
|
1611
|
+
function participant_access(name, room) {
|
|
1612
|
+
const adapter = (room?.members || []).find(member => member.name === name)?.adapter;
|
|
1613
|
+
if (adapter === "api") return "API";
|
|
1614
|
+
if (["codex", "antigravity"].includes(adapter)) return "App";
|
|
1615
|
+
return room?.experts?.[name] === "cli" ? "CLI" : "在线";
|
|
1616
|
+
}
|
|
1617
|
+
|
|
1610
1618
|
// App and web clients keep model selection in the original conversation.
|
|
1611
1619
|
const MODEL_CLIENTS = ["codex_cli", "claude", "antigravity_cli"];
|
|
1612
1620
|
const MODEL_SOURCE_LABELS = { "codex-app-server": "来自 Codex CLI 模型列表", "claude-cli": "来自 Claude CLI 模型列表", "antigravity-cli": "来自 Antigravity CLI 模型列表" };
|
|
@@ -2995,7 +3003,7 @@ window.discuss_view = { snapshot: view_snapshot, write_field: write_view_field,
|
|
|
2995
3003
|
attachment_markup, attachment_size, attachment_file_icon, drop_attachments, paste_attachments,
|
|
2996
3004
|
write_expert: write_view_expert, add_instance: add_view_instance, platform_of, execute: execute_view_action, theme: change_view_theme,
|
|
2997
3005
|
request: request_json, identities: IDENTITIES, display_name, sources: SOURCE_LABELS, phases: PHASE_LABELS,
|
|
2998
|
-
runtime_label, execution_label, limits_label, participant_model,
|
|
3006
|
+
runtime_label, execution_label, limits_label, participant_model, participant_access,
|
|
2999
3007
|
turns: TURN_LABELS, turn_label, turn_guidance, floor_status, progress_round, progress_speaker, brief_meta, max_message_length: MAX_MESSAGE_LENGTH, provenance: message_provenance, format_time };
|
|
3000
3008
|
|
|
3001
3009
|
restore_theme();
|