@worca/app 1.0.0-rc.1 → 1.1.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/README.md +22 -9
- package/agents/clarify.meta.json +4 -4
- package/agents/decomposer.meta.json +5 -5
- package/agents/implementer.meta.json +15 -5
- package/agents/manualTestsChecklist.meta.json +5 -4
- package/agents/manualWebUiTesting.meta.json +9 -4
- package/agents/planReviewer.meta.json +12 -4
- package/agents/planner.meta.json +12 -5
- package/agents/refiner.meta.json +15 -4
- package/agents/reviewer.meta.json +14 -4
- package/agents/worca-cc-clarify.md +7 -0
- package/agents/worca-cc-code-reviewer.md +11 -6
- package/agents/worca-cc-decomposer.md +7 -0
- package/agents/worca-cc-implementer.md +9 -0
- package/agents/worca-cc-manual-tests-checklist.md +8 -5
- package/agents/worca-cc-manual-web-ui-testing.md +10 -6
- package/agents/worca-cc-plan-refiner.md +11 -6
- package/agents/worca-cc-plan-reviewer.md +10 -7
- package/agents/worca-cc-planner.md +9 -0
- package/agents/worca-cc-workspace-reviewer.md +11 -4
- package/agents/worca-cc-workspace-scanner.md +8 -4
- package/agents/workspaceReviewer.meta.json +15 -4
- package/agents/workspaceScanner.meta.json +5 -4
- package/package.json +8 -2
- package/skills/worca/SKILL.md +5 -5
- package/src/cli/render.mjs +148 -0
- package/src/cli/worca-cc.mjs +319 -45
- package/src/core/agent-gen.mjs +69 -31
- package/src/core/agent-registry.mjs +124 -144
- package/src/core/agent-store.mjs +164 -4
- package/src/core/artifacts.mjs +189 -21
- package/src/core/ask/catalog.mjs +111 -0
- package/src/core/ask/comment-deps.mjs +55 -0
- package/src/core/ask/events.mjs +506 -0
- package/src/core/ask/follow.mjs +107 -0
- package/src/core/ask/git-allowlist.mjs +226 -0
- package/src/core/ask/limits.mjs +54 -0
- package/src/core/ask/mcp-stdio.mjs +135 -0
- package/src/core/ask/models.mjs +125 -0
- package/src/core/ask/prompt.mjs +261 -0
- package/src/core/ask/proposal.mjs +170 -0
- package/src/core/ask/redact.mjs +30 -0
- package/src/core/ask/spawn.mjs +153 -0
- package/src/core/ask/store.mjs +360 -0
- package/src/core/ask/tool-deps.mjs +63 -0
- package/src/core/ask/tools.mjs +848 -0
- package/src/core/ask/turn.mjs +416 -0
- package/src/core/ask/worktree-deps.mjs +27 -0
- package/src/core/ask/worktrees.mjs +285 -0
- package/src/core/chat/command-router.mjs +20 -3
- package/src/core/claude-runner.mjs +434 -57
- package/src/core/config.mjs +264 -41
- package/src/core/cost-budget.mjs +29 -2
- package/src/core/db.mjs +684 -47
- package/src/core/diff-anchor.mjs +213 -0
- package/src/core/diff-comments.mjs +273 -0
- package/src/core/engine-select.mjs +32 -0
- package/src/core/git-info.mjs +49 -10
- package/src/core/graph/builtin-workflows.mjs +51 -0
- package/src/core/graph/executor.mjs +894 -0
- package/src/core/graph/registry-ports.mjs +12 -0
- package/src/core/graph/scheduler.mjs +1065 -0
- package/src/core/graph/seed-templates.mjs +318 -0
- package/src/core/model-env.mjs +112 -8
- package/src/core/model-test.mjs +79 -0
- package/src/core/orchestrator.mjs +902 -4098
- package/src/core/overview-agent.mjs +15 -3
- package/src/core/phases.mjs +208 -537
- package/src/core/pipeline-delete.mjs +13 -2
- package/src/core/plugin-api.mjs +8 -3
- package/src/core/plugin-config.mjs +178 -28
- package/src/core/plugin-inventory.mjs +6 -2
- package/src/core/plugin-manifest.mjs +199 -11
- package/src/core/plugin-models.mjs +1 -0
- package/src/core/plugin-repo.mjs +16 -4
- package/src/core/plugin-shim-child.mjs +9 -3
- package/src/core/plugin-shim.mjs +77 -14
- package/src/core/plugin-store.mjs +236 -29
- package/src/core/plugin-workflows.mjs +90 -41
- package/src/core/preflight.mjs +135 -3
- package/src/core/projects.mjs +7 -5
- package/src/core/protocol.mjs +8 -35
- package/src/core/recoverable-error.mjs +1 -1
- package/src/core/run-harness.mjs +3585 -0
- package/src/core/run-manifest.mjs +5 -1
- package/src/core/settings.mjs +109 -13
- package/src/core/skills.mjs +10 -3
- package/src/core/source-bindings.mjs +175 -0
- package/src/core/sources.mjs +87 -25
- package/src/core/stats.mjs +25 -6
- package/src/core/title.mjs +51 -4
- package/src/core/workflows.mjs +358 -259
- package/src/core/workspace-scan.mjs +4 -0
- package/src/core/worktree.mjs +98 -7
- package/src/shared/graph/agent-meta.mjs +278 -0
- package/src/shared/graph/constants.mjs +105 -0
- package/src/shared/graph/geometry.mjs +157 -0
- package/src/shared/graph/layout.mjs +134 -0
- package/src/shared/graph/loops.mjs +130 -0
- package/src/shared/graph/manifest.mjs +257 -0
- package/src/shared/graph/ports.mjs +153 -0
- package/src/shared/graph/route.mjs +397 -0
- package/src/shared/graph/template.mjs +165 -0
- package/src/shared/graph/thumbnail.mjs +67 -0
- package/src/shared/graph/validate.mjs +491 -0
- package/src/shared/graph/verdict.mjs +41 -0
- package/ui/public/app.js +4008 -1670
- package/ui/public/ask-markdown.mjs +145 -0
- package/ui/public/ask-model.mjs +264 -0
- package/ui/public/ask-panel.mjs +1880 -0
- package/ui/public/chat-settings-view.mjs +6 -2
- package/ui/public/diff-view.mjs +66 -11
- package/ui/public/file-tree.mjs +305 -0
- package/ui/public/graph/composer.mjs +889 -0
- package/ui/public/graph/inspector.mjs +183 -0
- package/ui/public/graph/model.mjs +37 -0
- package/ui/public/graph/palette.mjs +144 -0
- package/ui/public/graph/run-decor.mjs +410 -0
- package/ui/public/graph/run-hosts.mjs +201 -0
- package/ui/public/graph/save-dialog.mjs +56 -0
- package/ui/public/graph/view.mjs +858 -0
- package/ui/public/guardrails-view.mjs +4 -2
- package/ui/public/hljs-loader.mjs +180 -0
- package/ui/public/index.html +269 -265
- package/ui/public/log-filter.mjs +22 -4
- package/ui/public/log-line.mjs +45 -19
- package/ui/public/models-view.mjs +171 -9
- package/ui/public/plugins-view.mjs +106 -4
- package/ui/public/source-pane.mjs +190 -8
- package/ui/public/stats-view.mjs +81 -1
- package/ui/public/style.css +1459 -229
- package/ui/public/syntax-highlight.mjs +270 -0
- package/ui/public/thinking-orb.mjs +110 -0
- package/ui/server.mjs +1667 -98
- package/src/core/channels.mjs +0 -302
- package/src/core/runners.mjs +0 -167
- package/src/core/workflow-validator.mjs +0 -185
- package/ui/public/composer-core.mjs +0 -211
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
// src/core/ask/catalog.mjs
|
|
2
|
+
// The static catalog the assistant sees (ask-worca-design.md §6.1, D9): projects,
|
|
3
|
+
// workspaces and workflows with their ordered step groups. ONE builder feeds both
|
|
4
|
+
// the system prompt (prompt.mjs renders a subset) and the list_projects /
|
|
5
|
+
// list_workflows tools (tools.mjs returns the objects) — never two readers.
|
|
6
|
+
// Readers are injected so unit tests run without a DB.
|
|
7
|
+
import { listProjects as realListProjects } from '../projects.mjs';
|
|
8
|
+
import { listWorkspaces as realListWorkspaces } from '../workspaces.mjs';
|
|
9
|
+
import { listWorkflows as realListWorkflows, GRAPH_DEFAULT_WORKFLOW } from '../workflows.mjs';
|
|
10
|
+
import { classifyLoops } from '../../shared/graph/loops.mjs';
|
|
11
|
+
import { rankNodes } from '../../shared/graph/layout.mjs';
|
|
12
|
+
import { registryPortsFn } from '../graph/registry-ports.mjs';
|
|
13
|
+
|
|
14
|
+
/** A v2 graph -> the v1-shaped step groups the assistant already understands:
|
|
15
|
+
* one group per rank (loop wires excluded), agent nodes only. */
|
|
16
|
+
function graphSteps(tpl, portsFn) {
|
|
17
|
+
const ranks = rankNodes(tpl, classifyLoops(tpl, portsFn));
|
|
18
|
+
const byRank = new Map();
|
|
19
|
+
for (const node of tpl.nodes) {
|
|
20
|
+
// buildCatalog maps EVERY template, so one malformed node used to take down
|
|
21
|
+
// the whole Ask system prompt and list_workflows, not just its own row.
|
|
22
|
+
if (!node || node.kind !== 'agent') continue;
|
|
23
|
+
const r = ranks[node.id] ?? 0;
|
|
24
|
+
if (!byRank.has(r)) byRank.set(r, []);
|
|
25
|
+
byRank.get(r).push(node);
|
|
26
|
+
}
|
|
27
|
+
return [...byRank.keys()].sort((a, b) => a - b).map((r) => byRank.get(r));
|
|
28
|
+
}
|
|
29
|
+
import { loadAgentRegistry as realLoadAgentRegistry } from '../agent-registry.mjs';
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Pure: a stored workflow template → the catalog shape. `tpl.steps` is already
|
|
33
|
+
* Array<Array<{id,key}>> (outer = ordered step groups, inner = parallel nodes,
|
|
34
|
+
* workflows.mjs:93-111 / :208-220), so this is a straight map against the agent
|
|
35
|
+
* registry for display names; unknown keys fall back to the key itself.
|
|
36
|
+
*/
|
|
37
|
+
export function shapeWorkflow(tpl, registry = {}) {
|
|
38
|
+
if (tpl && tpl.version === 2 && Array.isArray(tpl.nodes)) {
|
|
39
|
+
const portsFn = registryPortsFn(registry);
|
|
40
|
+
const groups = graphSteps(tpl, portsFn);
|
|
41
|
+
const { loopWireIds } = classifyLoops(tpl, portsFn);
|
|
42
|
+
return {
|
|
43
|
+
id: tpl.id,
|
|
44
|
+
name: tpl.name,
|
|
45
|
+
domain: typeof tpl.domain === 'string' && tpl.domain ? tpl.domain : 'general',
|
|
46
|
+
origin: tpl.origin ?? null,
|
|
47
|
+
steps: groups.map((group) => group.map((node) => {
|
|
48
|
+
const meta = registry && registry[node.key] ? registry[node.key] : null;
|
|
49
|
+
return {
|
|
50
|
+
nodeId: node.id,
|
|
51
|
+
key: node.key,
|
|
52
|
+
displayName: meta && meta.displayName ? meta.displayName : node.key,
|
|
53
|
+
description: meta && typeof meta.description === 'string' ? meta.description : '',
|
|
54
|
+
};
|
|
55
|
+
})),
|
|
56
|
+
feedbacks: (tpl.wires || []).filter((w) => w && loopWireIds.has(w.id))
|
|
57
|
+
.map((w) => ({ id: w.id, from: w.from.node, to: w.to.node })),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
const steps = Array.isArray(tpl.steps) ? tpl.steps : [];
|
|
61
|
+
const feedbacks = Array.isArray(tpl.feedbacks) ? tpl.feedbacks : [];
|
|
62
|
+
return {
|
|
63
|
+
id: tpl.id,
|
|
64
|
+
name: tpl.name,
|
|
65
|
+
domain: typeof tpl.domain === 'string' && tpl.domain ? tpl.domain : 'general',
|
|
66
|
+
origin: tpl.origin ?? null,
|
|
67
|
+
steps: steps.map((group) => (Array.isArray(group) ? group : []).map((node) => {
|
|
68
|
+
const meta = registry && node && registry[node.key] ? registry[node.key] : null;
|
|
69
|
+
return {
|
|
70
|
+
nodeId: node.id,
|
|
71
|
+
key: node.key,
|
|
72
|
+
displayName: meta && typeof meta.displayName === 'string' && meta.displayName ? meta.displayName : node.key,
|
|
73
|
+
description: meta && typeof meta.description === 'string' ? meta.description : '',
|
|
74
|
+
};
|
|
75
|
+
})),
|
|
76
|
+
feedbacks: feedbacks.map((f) => ({ id: f.id, from: f.from, to: f.to })),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* @param {{listProjects?:Function, listWorkspaces?:Function, listWorkflows?:Function, defaultWorkflow?:object, loadAgentRegistry?:Function}} [deps]
|
|
82
|
+
*/
|
|
83
|
+
export function createCatalog({
|
|
84
|
+
listProjects = realListProjects,
|
|
85
|
+
listWorkspaces = realListWorkspaces,
|
|
86
|
+
listWorkflows = realListWorkflows,
|
|
87
|
+
defaultWorkflow = GRAPH_DEFAULT_WORKFLOW,
|
|
88
|
+
loadAgentRegistry = realLoadAgentRegistry,
|
|
89
|
+
} = {}) {
|
|
90
|
+
async function buildCatalog() {
|
|
91
|
+
const [projects, workspaces, workflows] = await Promise.all([listProjects(), listWorkspaces(), listWorkflows()]);
|
|
92
|
+
let registry = {};
|
|
93
|
+
try { registry = loadAgentRegistry() || {}; } catch { registry = {}; }
|
|
94
|
+
// Same order as GET /api/workflows: the graph default, then saved rows.
|
|
95
|
+
// shapeWorkflow already derives `steps` (condensation-topo ranks) +
|
|
96
|
+
// `feedbacks` (loop wires) for a v2 template, so the LLM-facing shape is unchanged.
|
|
97
|
+
const templates = [
|
|
98
|
+
defaultWorkflow,
|
|
99
|
+
...workflows.filter((t) => t && t.id !== defaultWorkflow.id),
|
|
100
|
+
];
|
|
101
|
+
return {
|
|
102
|
+
projects: projects.map((p) => ({ key: p.key, name: p.name, path: p.path })),
|
|
103
|
+
workspaces: workspaces.map((w) => ({ id: w.id, name: w.name, projectKeys: [...(w.projectKeys || [])] })),
|
|
104
|
+
workflows: templates.map((t) => shapeWorkflow(t, registry)),
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
return { buildCatalog };
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** Bound to the real readers — what the server and the MCP child use. */
|
|
111
|
+
export const buildCatalog = createCatalog().buildCatalog;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// src/core/ask/comment-deps.mjs
|
|
2
|
+
// The WRITE-CAPABLE dep bundle of the diff-comment tools. Deliberately separate
|
|
3
|
+
// from tool-deps.mjs, whose source is scanned as read-only
|
|
4
|
+
// (test/ask-tools.test.mjs): every row that is created, resolved or deleted is
|
|
5
|
+
// reachable ONLY through here, and test/ask-diff-comment-tools.test.mjs pins this
|
|
6
|
+
// module's import surface. Same shape as worktree-deps.mjs — one namespaced
|
|
7
|
+
// sub-object.
|
|
8
|
+
//
|
|
9
|
+
// Everything writes through src/core/diff-comments.mjs — the one mutation module —
|
|
10
|
+
// so the MCP path and the REST path share anchor validation, the body cap and the
|
|
11
|
+
// change notification. Reads add the surrounding hunk lines here (tools.mjs has no
|
|
12
|
+
// imports at all); tools.mjs owns the protected-path filter and the redaction, so
|
|
13
|
+
// the fail-closed read rules live next to get_run_diff's.
|
|
14
|
+
import {
|
|
15
|
+
addDiffComment, listDiffComments, getDiffComment, setDiffCommentResolved, deleteDiffComment,
|
|
16
|
+
} from '../diff-comments.mjs';
|
|
17
|
+
import { hunkContext } from '../diff-anchor.mjs';
|
|
18
|
+
|
|
19
|
+
/** Rows either side of an anchor served to the model. */
|
|
20
|
+
export const COMMENT_CONTEXT_RADIUS = 3;
|
|
21
|
+
|
|
22
|
+
// COST NOTE, deliberate: hunkContext() re-runs splitPatchSections + patchIndex +
|
|
23
|
+
// parseFileSection over the WHOLE patch once per comment, so listing N comments
|
|
24
|
+
// on a run costs N full parses. That is the price of using the ONE parser (D3)
|
|
25
|
+
// instead of a second, faster, divergent one. It is bounded in practice — this
|
|
26
|
+
// runs in the MCP child, once per tool call, on runs with a handful of comments
|
|
27
|
+
// — and the REST list path does not do it at all. If a real run ever makes this
|
|
28
|
+
// hurt, memoize the parsed index per (patchText) inside this closure; do NOT
|
|
29
|
+
// hand-roll a cheaper scan.
|
|
30
|
+
|
|
31
|
+
/** No thread scoping: comments belong to RUNS, not to chat threads. */
|
|
32
|
+
export function defaultCommentDeps() {
|
|
33
|
+
return {
|
|
34
|
+
comments: {
|
|
35
|
+
/** Comments of a run, each with `context` when the patch is readable.
|
|
36
|
+
* `keep` is the CALLER's protected-path filter (tools.mjs owns the guard
|
|
37
|
+
* rules); applied BEFORE the context parse so a row that will be dropped
|
|
38
|
+
* never costs a whole-patch parse, and so the order is fail-closed-first
|
|
39
|
+
* like everywhere else. */
|
|
40
|
+
list: (storeKey, pipelineId, { status = 'all', path = null, patchText = null, keep = null } = {}) => {
|
|
41
|
+
const rows = listDiffComments(storeKey, pipelineId, { status, path });
|
|
42
|
+
const kept = typeof keep === 'function' ? rows.filter(keep) : rows;
|
|
43
|
+
return kept.map((c) => (patchText == null ? c : {
|
|
44
|
+
...c,
|
|
45
|
+
context: hunkContext(patchText, { project: c.projectKey, path: c.path, side: c.side, line: c.line },
|
|
46
|
+
COMMENT_CONTEXT_RADIUS),
|
|
47
|
+
}));
|
|
48
|
+
},
|
|
49
|
+
add: (input) => addDiffComment({ ...input, author: 'ask' }),
|
|
50
|
+
get: (id) => getDiffComment(id),
|
|
51
|
+
setResolved: (id, resolved) => setDiffCommentResolved(id, resolved),
|
|
52
|
+
remove: (id) => deleteDiffComment(id),
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
}
|