Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
1156aa5
fix(app): let conversation agents interpret free text
huangruiteng Sep 25, 2026
9bb41aa
docs: align App conversations and shared inbox delivery
huangruiteng Sep 25, 2026
52f3f06
fix(app): block Task and Goal drafts that exceed action limits
huangruiteng Sep 25, 2026
dc91b0a
feat(app): show Goal execution only from active session turns
huangruiteng Sep 25, 2026
47493cc
test(app): cover session-backed Goal execution in the browser suite
huangruiteng Sep 25, 2026
313aa00
feat(app): add a daily brief to the manager home
huangruiteng Sep 25, 2026
de30f0c
feat(app): name attached hosts and disclose silent turns
huangruiteng Sep 25, 2026
c84c585
test(app): wait for the steward settings readback after apply
huangruiteng Sep 25, 2026
dd41c1b
test(app): keep applied machine configuration in the browser fixture
huangruiteng Sep 25, 2026
3403ea8
fix(app): attribute host-owned Goals to bound threads and show attach…
huangruiteng Sep 25, 2026
8854cb4
feat(app): let the conversation lead the Goal Chat view
huangruiteng Sep 25, 2026
d04fd7d
test(app): select proposals by action kind and open background work
huangruiteng Sep 25, 2026
54fa6d1
fix(app): lead the Goal Chat with the newest pending draft
huangruiteng Sep 26, 2026
c99452a
test(app): serve the store's real proposal order and pin the rule
huangruiteng Sep 26, 2026
6c86b75
fix(app): report a host claim as a claim, not as execution activity
huangruiteng Sep 26, 2026
f7dc503
feat: show whether bound Codex threads are running in the App (#5081)
huangruiteng Sep 26, 2026
40bb86c
fix(app): keep a host claim out of the running brief and lane
huangruiteng Sep 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions apps/presentation/dashboard/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,15 @@
"smoke:frontstage-route": "rm -rf /tmp/loopx-frontstage-route-smoke && tsc --ignoreConfig --target ES2022 --module NodeNext --moduleResolution NodeNext --skipLibCheck --strict --outDir /tmp/loopx-frontstage-route-smoke smoke/frontstage-route-smoke.ts && node /tmp/loopx-frontstage-route-smoke/frontstage-route-smoke.js",
"smoke:frontstage-share-bundle": "node ../../../examples/frontstage-share-bundle-smoke.mjs",
"smoke:goal-order": "tsc --ignoreConfig --target ES2022 --module ES2022 --moduleResolution Bundler --skipLibCheck --strict --outDir node_modules/.cache/loopx-goal-order src/features/personal-workspace/goal-order.ts && node src/features/personal-workspace/goal-order.test.mjs",
"smoke:goal-activity": "tsc --ignoreConfig --target ES2022 --module ES2022 --moduleResolution Bundler --skipLibCheck --strict --outDir node_modules/.cache/loopx-goal-activity src/features/personal-workspace/goal-activity.ts && node src/features/personal-workspace/goal-activity.test.mjs",
"smoke:proposal-recency": "tsc --ignoreConfig --target ES2022 --module ES2022 --moduleResolution Bundler --skipLibCheck --strict --outDir node_modules/.cache/loopx-proposal-recency src/features/personal-workspace/proposal-recency.ts && node src/features/personal-workspace/proposal-recency.test.mjs",
"smoke:home-browser": "node ../../../examples/dashboard-home-browser-smoke.mjs",
"smoke:home-route": "rm -rf /tmp/loopx-home-route-smoke && tsc --ignoreConfig --target ES2022 --module CommonJS --moduleResolution Node --ignoreDeprecations 6.0 --skipLibCheck --strict --outDir /tmp/loopx-home-route-smoke smoke/home-route-smoke.ts && node /tmp/loopx-home-route-smoke/home-route-smoke.js",
"smoke:delegation-preflight": "rm -rf node_modules/.cache/loopx-delegation-preflight-smoke && tsc --ignoreConfig --target ES2022 --module NodeNext --moduleResolution NodeNext --jsx react-jsx --skipLibCheck --strict --rootDir . --outDir node_modules/.cache/loopx-delegation-preflight-smoke smoke/delegation-preflight-smoke.tsx src/data/delegation-preflight.ts src/features/personal-workspace/delegation-preflight-status.tsx && node node_modules/.cache/loopx-delegation-preflight-smoke/smoke/delegation-preflight-smoke.js",
"smoke:personal-workspace": "npm run smoke:goal-order && npm run smoke:delegation-preflight && node src/features/personal-workspace/workspace-theme.test.mjs && node src/features/personal-workspace/personal-workspace-contract.test.mjs && node ../../../examples/personal-workspace-browser-smoke.mjs",
"smoke:personal-workspace": "npm run smoke:goal-order && npm run smoke:goal-activity && npm run smoke:proposal-recency && npm run smoke:delegation-preflight && node src/features/personal-workspace/workspace-theme.test.mjs && node src/features/personal-workspace/personal-workspace-contract.test.mjs && node ../../../examples/personal-workspace-browser-smoke.mjs",
"smoke:workspace-locale": "LOOPX_PERSONAL_WORKSPACE_SCENARIO=workspace-locale node ../../../examples/personal-workspace-browser-smoke.mjs",
"smoke:personal-workspace-packaged": "npm run smoke:goal-order && npm run smoke:delegation-preflight && node src/features/personal-workspace/workspace-theme.test.mjs && node src/features/personal-workspace/personal-workspace-contract.test.mjs && LOOPX_PERSONAL_WORKSPACE_PACKAGED=1 LOOPX_PLAYWRIGHT_PACKAGE=\"$PWD/node_modules/playwright\" node ../../../examples/personal-workspace-browser-smoke.mjs",
"smoke:personal-workspace-router": "rm -rf /tmp/loopx-personal-workspace-router-smoke && tsc --ignoreConfig --target ES2022 --module commonjs --moduleResolution node --ignoreDeprecations 6.0 --skipLibCheck --strict --outDir /tmp/loopx-personal-workspace-router-smoke smoke/personal-workspace-router-smoke.ts src/features/personal-workspace/personal-workspace-router.ts && node /tmp/loopx-personal-workspace-router-smoke/smoke/personal-workspace-router-smoke.js",
"smoke:personal-workspace-packaged": "npm run smoke:goal-order && npm run smoke:goal-activity && npm run smoke:proposal-recency && npm run smoke:delegation-preflight && node src/features/personal-workspace/workspace-theme.test.mjs && node src/features/personal-workspace/personal-workspace-contract.test.mjs && LOOPX_PERSONAL_WORKSPACE_PACKAGED=1 LOOPX_PLAYWRIGHT_PACKAGE=\"$PWD/node_modules/playwright\" node ../../../examples/personal-workspace-browser-smoke.mjs",
"smoke:todo-resume-condition": "rm -rf /tmp/loopx-todo-resume-condition-smoke && tsc --ignoreConfig --target ES2022 --module commonjs --moduleResolution node --ignoreDeprecations 6.0 --skipLibCheck --strict --outDir /tmp/loopx-todo-resume-condition-smoke smoke/todo-resume-condition-smoke.ts src/features/personal-workspace/todo-resume-condition.ts && node /tmp/loopx-todo-resume-condition-smoke/smoke/todo-resume-condition-smoke.js",
"smoke:presentation-surface-schema": "rm -rf /tmp/loopx-presentation-surface-schema-smoke && tsc --ignoreConfig --target ES2022 --module CommonJS --moduleResolution Node --ignoreDeprecations 6.0 --skipLibCheck --strict --resolveJsonModule --esModuleInterop --outDir /tmp/loopx-presentation-surface-schema-smoke smoke/presentation-surface-schema-smoke.ts src/data/status.ts src/data/decision-research.ts src/data/goal-channel-frontstage.ts && NODE_PATH=\"$PWD/node_modules\" node /tmp/loopx-presentation-surface-schema-smoke/apps/presentation/dashboard/smoke/presentation-surface-schema-smoke.js",
"smoke:projection-localization": "rm -rf /tmp/loopx-projection-localization-smoke && tsc --ignoreConfig --target ES2022 --module NodeNext --moduleResolution NodeNext --skipLibCheck --strict --outDir /tmp/loopx-projection-localization-smoke smoke/projection-localization-smoke.ts src/features/personal-workspace/projection-localization.ts && node /tmp/loopx-projection-localization-smoke/smoke/projection-localization-smoke.js",
"smoke:pwa-bundle": "python3 ../../../examples/dashboard-pwa-bundle-smoke.py",
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
type Values = Record<string, string | number>;

const english = {
"projection.agentAdvancingGoal": "Agent is advancing the current Goal",
"projection.agentWorkQueued": "Agent work is queued for this Goal",
"projection.agentIdle": "Nothing needs your attention",
"projection.agentNeedsDecision": "Agent is waiting for your decision",
"projection.agentPreparingNextStep": "Agent is preparing the next step",
Expand All @@ -21,7 +21,7 @@ const english = {
} as const;

const chinese = {
"projection.agentAdvancingGoal": "Agent 正在推进当前 Goal",
"projection.agentWorkQueued": "这个 Goal 有待 Agent 推进的工作",
"projection.agentIdle": "暂无需要你处理",
"projection.agentNeedsDecision": "Agent 等待你的决定",
"projection.agentPreparingNextStep": "Agent 正在整理下一步",
Expand Down Expand Up @@ -63,23 +63,23 @@ const en = translator(english);
const zhCN = translator(chinese);

equal(
projectionSentence("loopx check --format json", en, "projection.agentAdvancingGoal"),
"Agent is advancing the current Goal",
"English command-like projection uses the localized advancing fallback",
projectionSentence("loopx check --format json", en, "projection.agentWorkQueued"),
"Agent work is queued for this Goal",
"English command-like projection uses the localized queued-work fallback",
);
equal(
projectionSentence("loopx check --format json", zhCN, "projection.agentAdvancingGoal"),
"Agent 正在推进当前 Goal",
"Chinese command-like projection preserves the localized advancing fallback",
projectionSentence("loopx check --format json", zhCN, "projection.agentWorkQueued"),
"这个 Goal 有待 Agent 推进的工作",
"Chinese command-like projection preserves the localized queued-work fallback",
);
equal(
projectionSentence("Review the project-specific adapter signal", en, "projection.agentAdvancingGoal"),
projectionSentence("Review the project-specific adapter signal", en, "projection.agentWorkQueued"),
"Review the project-specific adapter signal",
"Source-authored projection text remains unchanged",
);

equal(agentStatusSentence("needs_you", en), "Agent is waiting for your decision", "English needs-you status");
equal(agentStatusSentence("advancing", en), "Agent is advancing the current Goal", "English advancing status");
equal(agentStatusSentence("queued", en), "Agent work is queued for this Goal", "English queued-work status");
equal(agentStatusSentence("waiting_external", en), "Waiting for an external condition", "English external-wait status");
equal(agentStatusSentence("idle", en), "Nothing needs your attention", "English idle status");
equal(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { parseTodoResumeCondition } from "../src/features/personal-workspace/todo-resume-condition.js";

for (const condition of ["todo_done:todo_release", "pr_merged:example/project#42", "capacity_available:worker", "resume_at:2026-10-01T09:00:00Z"]) {
if (parseTodoResumeCondition(condition) !== condition.toLowerCase()) throw new Error(`Supported resume condition rejected: ${condition}`);
}
for (const value of ["tomorrow", "owner_resume", "pr_merged:#0", "todo_done:", "resume_at:2026-10-01"]) {
if (parseTodoResumeCondition(value) !== null) throw new Error(`Unsupported resume condition admitted: ${value}`);
}
console.log("todo-resume-condition-smoke: ok");
2 changes: 2 additions & 0 deletions apps/presentation/dashboard/src/data/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -661,6 +661,8 @@ export type ChatSessionSummary = {
updated_at: string;
last_activity_at: string;
resumable: boolean;
session_mode?: string;
host_surface?: string | null;
manager_runtime?: ManagerRuntimeSessionReadback | null;
};

Expand Down
19 changes: 19 additions & 0 deletions apps/presentation/dashboard/src/data/status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -521,7 +521,26 @@ export const runGoalSchema = z.object({
coordination: z.object({
agent_model: z.string().optional().nullable(),
registered_agents: z.array(z.string()).optional().default([]),
// Opaque host thread ids stay out of the App state.
thread_agent_bindings: z.array(z.object({
agent_id: z.string().optional().nullable(),
host_surface: z.string().optional().nullable(),
})).optional().default([]).catch([]),
}).optional().nullable(),
host_thread_activity: z.object({
observed_at: z.string().optional().nullable(),
// Older or malformed observations cannot prove that every binding was read.
completeness: z.enum(["complete", "incomplete"]).catch("incomplete").default("incomplete"),
threads: z.array(z.object({
agent_id: z.string().optional().nullable(),
host_surface: z.string(),
state: z.enum(["turn_open", "idle", "archived", "unknown"]).catch("unknown"),
reason: z.string().optional().nullable(),
turn_started_at: z.string().optional().nullable(),
last_turn_ended_at: z.string().optional().nullable(),
last_event_at: z.string().optional().nullable(),
})).optional().default([]),
}).optional().nullable().catch(null),
index_exists: z.boolean().optional().default(false),
raw_index_records: z.number().optional().default(0),
unique_runs: z.number().optional().default(0),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Bot, Eye, Menu, RefreshCw, SlidersHorizontal } from "lucide-react";
import { GoalActivityChip } from "./goal-activity-view";

import { localizedGoalState, useWorkspaceI18n } from "./i18n";
import type { ManagerChannelBinding, ManagerRuntimeSessionReadback } from "../../data/chat";
Expand Down Expand Up @@ -135,7 +136,7 @@ export function ChannelHeader({
<button aria-expanded={mobileNavigationOpen ?? false} aria-label={t("header.openGoalNavigation")} className="personal-icon-button personal-mobile-menu" onClick={onOpenNavigation} type="button"><Menu size={18} /></button>
<div className="personal-channel-title">
<h1>{selectedGoal?.title ?? t("header.manager")}</h1>
{selectedGoal && !selectedGoal.loadState && !["安静运行", "推进中"].includes(selectedGoal.state) ? <p>{localizedGoalState(selectedGoal.state, locale)}</p> : null}
{selectedGoal && !selectedGoal.loadState ? <p className="personal-channel-activity"><GoalActivityChip goal={selectedGoal} /></p> : null}
{!selectedGoal && managerChannelBinding ? (
<p className="personal-manager-execution">
<span className={managerExecutionUnavailable ? "personal-execution-chip is-unavailable" : "personal-execution-chip"}>
Expand Down
Loading
Loading