@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.
Files changed (138) hide show
  1. package/README.md +22 -9
  2. package/agents/clarify.meta.json +4 -4
  3. package/agents/decomposer.meta.json +5 -5
  4. package/agents/implementer.meta.json +15 -5
  5. package/agents/manualTestsChecklist.meta.json +5 -4
  6. package/agents/manualWebUiTesting.meta.json +9 -4
  7. package/agents/planReviewer.meta.json +12 -4
  8. package/agents/planner.meta.json +12 -5
  9. package/agents/refiner.meta.json +15 -4
  10. package/agents/reviewer.meta.json +14 -4
  11. package/agents/worca-cc-clarify.md +7 -0
  12. package/agents/worca-cc-code-reviewer.md +11 -6
  13. package/agents/worca-cc-decomposer.md +7 -0
  14. package/agents/worca-cc-implementer.md +9 -0
  15. package/agents/worca-cc-manual-tests-checklist.md +8 -5
  16. package/agents/worca-cc-manual-web-ui-testing.md +10 -6
  17. package/agents/worca-cc-plan-refiner.md +11 -6
  18. package/agents/worca-cc-plan-reviewer.md +10 -7
  19. package/agents/worca-cc-planner.md +9 -0
  20. package/agents/worca-cc-workspace-reviewer.md +11 -4
  21. package/agents/worca-cc-workspace-scanner.md +8 -4
  22. package/agents/workspaceReviewer.meta.json +15 -4
  23. package/agents/workspaceScanner.meta.json +5 -4
  24. package/package.json +8 -2
  25. package/skills/worca/SKILL.md +5 -5
  26. package/src/cli/render.mjs +148 -0
  27. package/src/cli/worca-cc.mjs +319 -45
  28. package/src/core/agent-gen.mjs +69 -31
  29. package/src/core/agent-registry.mjs +124 -144
  30. package/src/core/agent-store.mjs +164 -4
  31. package/src/core/artifacts.mjs +189 -21
  32. package/src/core/ask/catalog.mjs +111 -0
  33. package/src/core/ask/comment-deps.mjs +55 -0
  34. package/src/core/ask/events.mjs +506 -0
  35. package/src/core/ask/follow.mjs +107 -0
  36. package/src/core/ask/git-allowlist.mjs +226 -0
  37. package/src/core/ask/limits.mjs +54 -0
  38. package/src/core/ask/mcp-stdio.mjs +135 -0
  39. package/src/core/ask/models.mjs +125 -0
  40. package/src/core/ask/prompt.mjs +261 -0
  41. package/src/core/ask/proposal.mjs +170 -0
  42. package/src/core/ask/redact.mjs +30 -0
  43. package/src/core/ask/spawn.mjs +153 -0
  44. package/src/core/ask/store.mjs +360 -0
  45. package/src/core/ask/tool-deps.mjs +63 -0
  46. package/src/core/ask/tools.mjs +848 -0
  47. package/src/core/ask/turn.mjs +416 -0
  48. package/src/core/ask/worktree-deps.mjs +27 -0
  49. package/src/core/ask/worktrees.mjs +285 -0
  50. package/src/core/chat/command-router.mjs +20 -3
  51. package/src/core/claude-runner.mjs +434 -57
  52. package/src/core/config.mjs +264 -41
  53. package/src/core/cost-budget.mjs +29 -2
  54. package/src/core/db.mjs +684 -47
  55. package/src/core/diff-anchor.mjs +213 -0
  56. package/src/core/diff-comments.mjs +273 -0
  57. package/src/core/engine-select.mjs +32 -0
  58. package/src/core/git-info.mjs +49 -10
  59. package/src/core/graph/builtin-workflows.mjs +51 -0
  60. package/src/core/graph/executor.mjs +894 -0
  61. package/src/core/graph/registry-ports.mjs +12 -0
  62. package/src/core/graph/scheduler.mjs +1065 -0
  63. package/src/core/graph/seed-templates.mjs +318 -0
  64. package/src/core/model-env.mjs +112 -8
  65. package/src/core/model-test.mjs +79 -0
  66. package/src/core/orchestrator.mjs +902 -4098
  67. package/src/core/overview-agent.mjs +15 -3
  68. package/src/core/phases.mjs +208 -537
  69. package/src/core/pipeline-delete.mjs +13 -2
  70. package/src/core/plugin-api.mjs +8 -3
  71. package/src/core/plugin-config.mjs +178 -28
  72. package/src/core/plugin-inventory.mjs +6 -2
  73. package/src/core/plugin-manifest.mjs +199 -11
  74. package/src/core/plugin-models.mjs +1 -0
  75. package/src/core/plugin-repo.mjs +16 -4
  76. package/src/core/plugin-shim-child.mjs +9 -3
  77. package/src/core/plugin-shim.mjs +77 -14
  78. package/src/core/plugin-store.mjs +236 -29
  79. package/src/core/plugin-workflows.mjs +90 -41
  80. package/src/core/preflight.mjs +135 -3
  81. package/src/core/projects.mjs +7 -5
  82. package/src/core/protocol.mjs +8 -35
  83. package/src/core/recoverable-error.mjs +1 -1
  84. package/src/core/run-harness.mjs +3585 -0
  85. package/src/core/run-manifest.mjs +5 -1
  86. package/src/core/settings.mjs +109 -13
  87. package/src/core/skills.mjs +10 -3
  88. package/src/core/source-bindings.mjs +175 -0
  89. package/src/core/sources.mjs +87 -25
  90. package/src/core/stats.mjs +25 -6
  91. package/src/core/title.mjs +51 -4
  92. package/src/core/workflows.mjs +358 -259
  93. package/src/core/workspace-scan.mjs +4 -0
  94. package/src/core/worktree.mjs +98 -7
  95. package/src/shared/graph/agent-meta.mjs +278 -0
  96. package/src/shared/graph/constants.mjs +105 -0
  97. package/src/shared/graph/geometry.mjs +157 -0
  98. package/src/shared/graph/layout.mjs +134 -0
  99. package/src/shared/graph/loops.mjs +130 -0
  100. package/src/shared/graph/manifest.mjs +257 -0
  101. package/src/shared/graph/ports.mjs +153 -0
  102. package/src/shared/graph/route.mjs +397 -0
  103. package/src/shared/graph/template.mjs +165 -0
  104. package/src/shared/graph/thumbnail.mjs +67 -0
  105. package/src/shared/graph/validate.mjs +491 -0
  106. package/src/shared/graph/verdict.mjs +41 -0
  107. package/ui/public/app.js +4008 -1670
  108. package/ui/public/ask-markdown.mjs +145 -0
  109. package/ui/public/ask-model.mjs +264 -0
  110. package/ui/public/ask-panel.mjs +1880 -0
  111. package/ui/public/chat-settings-view.mjs +6 -2
  112. package/ui/public/diff-view.mjs +66 -11
  113. package/ui/public/file-tree.mjs +305 -0
  114. package/ui/public/graph/composer.mjs +889 -0
  115. package/ui/public/graph/inspector.mjs +183 -0
  116. package/ui/public/graph/model.mjs +37 -0
  117. package/ui/public/graph/palette.mjs +144 -0
  118. package/ui/public/graph/run-decor.mjs +410 -0
  119. package/ui/public/graph/run-hosts.mjs +201 -0
  120. package/ui/public/graph/save-dialog.mjs +56 -0
  121. package/ui/public/graph/view.mjs +858 -0
  122. package/ui/public/guardrails-view.mjs +4 -2
  123. package/ui/public/hljs-loader.mjs +180 -0
  124. package/ui/public/index.html +269 -265
  125. package/ui/public/log-filter.mjs +22 -4
  126. package/ui/public/log-line.mjs +45 -19
  127. package/ui/public/models-view.mjs +171 -9
  128. package/ui/public/plugins-view.mjs +106 -4
  129. package/ui/public/source-pane.mjs +190 -8
  130. package/ui/public/stats-view.mjs +81 -1
  131. package/ui/public/style.css +1459 -229
  132. package/ui/public/syntax-highlight.mjs +270 -0
  133. package/ui/public/thinking-orb.mjs +110 -0
  134. package/ui/server.mjs +1667 -98
  135. package/src/core/channels.mjs +0 -302
  136. package/src/core/runners.mjs +0 -167
  137. package/src/core/workflow-validator.mjs +0 -185
  138. 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
+ }