crow-central-agency 0.27.0 → 0.27.2
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 +1 -0
- package/dist/_shared/auto-approve/auto-approve-rule-set.js +3 -2
- package/dist/_shared/auto-approve/command-decomposition.js +47 -63
- package/dist/_shared/auto-approve/rule-strategies.js +10 -8
- package/dist/_shared/index.js +3 -2
- package/dist/_shared/schemas/graph.schema.js +8 -0
- package/dist/_shared/utils/mcp-utils.js +4 -0
- package/dist/bootstrap.js +1 -1
- package/dist/config/env.js +1 -0
- package/dist/feed/simply-feed-manager.js +1 -2
- package/dist/mcp/artifacts/write-artifact.js +3 -0
- package/dist/mcp/artifacts/write-circle-artifact.js +3 -0
- package/dist/mcp/crow-mcp-manager.js +2 -5
- package/dist/public/assets/{architectureDiagram-3BPJPVTR-B81-2nJq.js → architectureDiagram-3BPJPVTR-CClJU70x.js} +1 -1
- package/dist/public/assets/{chunk-727SXJPM-CA5zpRF4.js → chunk-727SXJPM-BAondkhN.js} +1 -1
- package/dist/public/assets/{chunk-AQP2D5EJ-BfWilfr3.js → chunk-AQP2D5EJ-kM5I-WKN.js} +1 -1
- package/dist/public/assets/{classDiagram-v2-Q7XG4LA2-hSZP-zK7.js → classDiagram-4FO5ZUOK-Dgr7qiRI.js} +1 -1
- package/dist/public/assets/{classDiagram-4FO5ZUOK-hSZP-zK7.js → classDiagram-v2-Q7XG4LA2-Dgr7qiRI.js} +1 -1
- package/dist/public/assets/{dagre-BM42HDAG-Du7tE18Y.js → dagre-BM42HDAG-DKTzSm29.js} +1 -1
- package/dist/public/assets/{diagram-2AECGRRQ-BtisML-9.js → diagram-2AECGRRQ-5PrRefQL.js} +1 -1
- package/dist/public/assets/{diagram-5GNKFQAL-4XFQLBWU.js → diagram-5GNKFQAL-DKTGe-Ql.js} +1 -1
- package/dist/public/assets/{diagram-LMA3HP47-CADs130y.js → diagram-LMA3HP47-Bb2RaPM2.js} +1 -1
- package/dist/public/assets/{diagram-OG6HWLK6-B0wqIPgk.js → diagram-OG6HWLK6-B-tad09d.js} +1 -1
- package/dist/public/assets/{erDiagram-TEJ5UH35-yQjnWqYr.js → erDiagram-TEJ5UH35-BL7n_6V6.js} +1 -1
- package/dist/public/assets/{flowDiagram-I6XJVG4X-DQyaPhc_.js → flowDiagram-I6XJVG4X-BLdaPh9i.js} +1 -1
- package/dist/public/assets/index-YTL1DK3j.css +1 -0
- package/dist/public/assets/index-uXjCHDqs.js +506 -0
- package/dist/public/assets/{infoDiagram-5YYISTIA-BDbevxAp.js → infoDiagram-5YYISTIA-CW9DCQBr.js} +1 -1
- package/dist/public/assets/{ishikawaDiagram-YF4QCWOH-Bsu77_Yo.js → ishikawaDiagram-YF4QCWOH-CwgrER31.js} +1 -1
- package/dist/public/assets/{kanban-definition-UN3LZRKU-f64whSnz.js → kanban-definition-UN3LZRKU-D1TuBRHr.js} +1 -1
- package/dist/public/assets/{mindmap-definition-RKZ34NQL-DfWnXOfI.js → mindmap-definition-RKZ34NQL-BtOi3_hU.js} +1 -1
- package/dist/public/assets/{pieDiagram-4H26LBE5-Bqg7-q_N.js → pieDiagram-4H26LBE5-DDo-JQZU.js} +1 -1
- package/dist/public/assets/{requirementDiagram-4Y6WPE33-cip1_k9k.js → requirementDiagram-4Y6WPE33-ghmfv1SX.js} +1 -1
- package/dist/public/assets/{sequenceDiagram-3UESZ5HK-CheQJr2g.js → sequenceDiagram-3UESZ5HK-D9BnXt7s.js} +1 -1
- package/dist/public/assets/{stateDiagram-AJRCARHV-an7e6llz.js → stateDiagram-AJRCARHV-BfaEy_5w.js} +1 -1
- package/dist/public/assets/{stateDiagram-v2-BHNVJYJU-BNydHOrt.js → stateDiagram-v2-BHNVJYJU-CTwOziWy.js} +1 -1
- package/dist/public/assets/{timeline-definition-PNZ67QCA-DoYJE76o.js → timeline-definition-PNZ67QCA-pAl_71QE.js} +1 -1
- package/dist/public/assets/{vennDiagram-CIIHVFJN-CtoH0FT3.js → vennDiagram-CIIHVFJN-DzbKt_lu.js} +1 -1
- package/dist/public/assets/{wardleyDiagram-YWT4CUSO-BgAGL7w8.js → wardleyDiagram-YWT4CUSO-CxEPL2m6.js} +1 -1
- package/dist/public/assets/{xychartDiagram-2RQKCTM6-B8gJqy0A.js → xychartDiagram-2RQKCTM6-B9a3Jq4J.js} +1 -1
- package/dist/public/index.html +2 -2
- package/dist/routes/fragment.routes.js +5 -0
- package/dist/routes/graph.routes.js +34 -6
- package/dist/runner/claude-code-agent-runner.js +1 -0
- package/dist/runner/github-copilot-agent-runner.js +44 -21
- package/dist/runner/github-copilot-permission.js +50 -0
- package/dist/services/relationship-manager.js +48 -6
- package/dist/utils/logger.js +2 -2
- package/package.json +1 -1
- package/dist/public/assets/index-BX-BOG4C.js +0 -506
- package/dist/public/assets/index-TfuJyPCv.css +0 -1
package/README.md
CHANGED
|
@@ -95,6 +95,7 @@ See `.env.example` for the full list, including:
|
|
|
95
95
|
- `HOST` / `PORT` — server bind address (defaults: `localhost:3101`). Keep `HOST=localhost` and front the server with a secure tunnel for remote access rather than binding to `0.0.0.0`.
|
|
96
96
|
- `CORS_ORIGINS` — only needed when the frontend is served from a different origin (e.g. during frontend dev). Single-box deployments can leave it unset.
|
|
97
97
|
- `LOG_LEVEL` — log verbosity (defaults to `debug` in development, `info` otherwise).
|
|
98
|
+
- `LOG_PRETTY` — force human-readable, colorized logs (pino-pretty) even in production. Enabled automatically in development.
|
|
98
99
|
- `CROW_SYSTEM_PATH` — directory for Crow's file-based storage. Defaults to `~/.crow`.
|
|
99
100
|
- `CROW_SYSTEM_AGENT_NAME` — display name for the built-in Crow system agent (default: `Crow`).
|
|
100
101
|
- `CROW_SYSTEM_AGENT_PROVIDER` — provider backing the built-in system agents: `claude` or `copilot` (default: `claude`). Forced to `claude` when `DISABLE_GITHUB_COPILOT` is set.
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SUBCOMMAND_MATCH_MODE } from "./command-decomposition.js";
|
|
1
2
|
import { parseRule } from "./rule-format.js";
|
|
2
3
|
import { getRuleStrategy } from "./rule-strategy-registry.js";
|
|
3
4
|
/**
|
|
@@ -23,8 +24,8 @@ export class AutoApproveRuleSet {
|
|
|
23
24
|
}
|
|
24
25
|
}
|
|
25
26
|
}
|
|
26
|
-
matches(toolName, input) {
|
|
27
|
-
return getRuleStrategy(toolName).matches(toolName, input, this.parsed);
|
|
27
|
+
matches(toolName, input, mode = SUBCOMMAND_MATCH_MODE.ALL) {
|
|
28
|
+
return getRuleStrategy(toolName).matches(toolName, input, this.parsed, mode);
|
|
28
29
|
}
|
|
29
30
|
}
|
|
30
31
|
//# sourceMappingURL=auto-approve-rule-set.js.map
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import { matchesSpecifier, WORD_BOUNDARY_SUFFIX } from "./rule-format.js";
|
|
2
|
-
/**
|
|
3
|
-
export const DEFAULT_PREFIX_DEPTH =
|
|
2
|
+
/** Number of non-flag tokens a derived prefix keeps before wildcarding the rest. */
|
|
3
|
+
export const DEFAULT_PREFIX_DEPTH = 3;
|
|
4
|
+
/**
|
|
5
|
+
* How a compound command aggregates per-subcommand matches. `ALL` (approve) requires every
|
|
6
|
+
* subcommand to match a specifier; `ANY` (deny) fires when a single subcommand matches.
|
|
7
|
+
*/
|
|
8
|
+
export const SUBCOMMAND_MATCH_MODE = {
|
|
9
|
+
ALL: "all",
|
|
10
|
+
ANY: "any",
|
|
11
|
+
};
|
|
4
12
|
/** Maximum number of rules derived from a single compound command, mirroring the SDK cap. */
|
|
5
13
|
export const MAX_DERIVED_RULES = 5;
|
|
6
14
|
/**
|
|
@@ -16,29 +24,7 @@ export const SINGLE_CHAR_SEPARATORS = [";", "|", "&", "\n", "\r"];
|
|
|
16
24
|
export const PROCESS_WRAPPERS = new Set(["timeout", "time", "nice", "nohup", "stdbuf"]);
|
|
17
25
|
const WRAPPERS_WITH_NUMERIC_ARG = new Set(["timeout", "nice"]);
|
|
18
26
|
const XARGS_WRAPPER = "xargs";
|
|
19
|
-
|
|
20
|
-
* Read-only shell builtins that run with no prompt. `cd` and `git` are handled separately
|
|
21
|
-
* (in-cwd `cd` only; read-only `git` subcommands only).
|
|
22
|
-
*/
|
|
23
|
-
export const READ_ONLY_BUILTINS = new Set([
|
|
24
|
-
"ls",
|
|
25
|
-
"cat",
|
|
26
|
-
"echo",
|
|
27
|
-
"pwd",
|
|
28
|
-
"head",
|
|
29
|
-
"tail",
|
|
30
|
-
"grep",
|
|
31
|
-
"find",
|
|
32
|
-
"wc",
|
|
33
|
-
"which",
|
|
34
|
-
"diff",
|
|
35
|
-
"stat",
|
|
36
|
-
"du",
|
|
37
|
-
]);
|
|
38
|
-
const CD_COMMAND = "cd";
|
|
39
|
-
const IN_CWD_CD_ARGS = new Set([".", "./"]);
|
|
40
|
-
const GIT_COMMAND = "git";
|
|
41
|
-
const READ_ONLY_GIT_SUBCOMMANDS = new Set(["status", "log", "diff", "show"]);
|
|
27
|
+
const OPTION_PREFIX = "-";
|
|
42
28
|
const SINGLE_QUOTE = "'";
|
|
43
29
|
const DOUBLE_QUOTE = '"';
|
|
44
30
|
const REDIRECT_CHAR = ">";
|
|
@@ -109,7 +95,7 @@ function stripWrappers(tokens) {
|
|
|
109
95
|
if (head === XARGS_WRAPPER) {
|
|
110
96
|
// Only bare `xargs` (no flags) is transparent; flagged xargs stays and simply won't match.
|
|
111
97
|
const next = remaining[1];
|
|
112
|
-
if (next !== undefined && next.startsWith(
|
|
98
|
+
if (next !== undefined && next.startsWith(OPTION_PREFIX)) {
|
|
113
99
|
break;
|
|
114
100
|
}
|
|
115
101
|
remaining = remaining.slice(1);
|
|
@@ -119,7 +105,7 @@ function stripWrappers(tokens) {
|
|
|
119
105
|
break;
|
|
120
106
|
}
|
|
121
107
|
remaining = remaining.slice(1);
|
|
122
|
-
while (remaining.length > 0 && remaining[0].startsWith(
|
|
108
|
+
while (remaining.length > 0 && remaining[0].startsWith(OPTION_PREFIX)) {
|
|
123
109
|
remaining = remaining.slice(1);
|
|
124
110
|
}
|
|
125
111
|
if (WRAPPERS_WITH_NUMERIC_ARG.has(head) && remaining.length > 0 && /^[0-9]/.test(remaining[0])) {
|
|
@@ -174,26 +160,31 @@ export function splitSubcommands(command) {
|
|
|
174
160
|
}
|
|
175
161
|
return subcommands;
|
|
176
162
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
163
|
+
function derivePrefixTokens(tokens, depth) {
|
|
164
|
+
const prefix = [];
|
|
165
|
+
let counted = 0;
|
|
166
|
+
let index = 0;
|
|
167
|
+
while (index < tokens.length && counted < depth) {
|
|
168
|
+
const token = tokens[index];
|
|
169
|
+
if (token.startsWith(OPTION_PREFIX)) {
|
|
170
|
+
prefix.push(token);
|
|
171
|
+
index += 1;
|
|
172
|
+
if (index < tokens.length && !tokens[index].startsWith(OPTION_PREFIX)) {
|
|
173
|
+
prefix.push(tokens[index]);
|
|
174
|
+
index += 1;
|
|
175
|
+
}
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
prefix.push(token);
|
|
179
|
+
counted += 1;
|
|
180
|
+
index += 1;
|
|
191
181
|
}
|
|
192
|
-
return
|
|
182
|
+
return counted === 0 ? undefined : prefix;
|
|
193
183
|
}
|
|
194
184
|
/**
|
|
195
|
-
* Capture side: derive one prefix
|
|
196
|
-
*
|
|
185
|
+
* Capture side: derive one flag-aware prefix specifier per subcommand, deduped and capped at
|
|
186
|
+
* {@link MAX_DERIVED_RULES}. A subcommand with no non-flag token (e.g. a lone `--flag`) contributes
|
|
187
|
+
* nothing. User config is the only auto-approve authority — there is no read-only skip.
|
|
197
188
|
*/
|
|
198
189
|
export function deriveRules(command, depth = DEFAULT_PREFIX_DEPTH) {
|
|
199
190
|
const specifiers = [];
|
|
@@ -201,15 +192,11 @@ export function deriveRules(command, depth = DEFAULT_PREFIX_DEPTH) {
|
|
|
201
192
|
if (specifiers.length >= MAX_DERIVED_RULES) {
|
|
202
193
|
break;
|
|
203
194
|
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
}
|
|
207
|
-
const tokens = tokenize(subcommand);
|
|
208
|
-
if (tokens.length === 0) {
|
|
195
|
+
const prefixTokens = derivePrefixTokens(tokenize(subcommand), depth);
|
|
196
|
+
if (prefixTokens === undefined) {
|
|
209
197
|
continue;
|
|
210
198
|
}
|
|
211
|
-
const
|
|
212
|
-
const specifier = `${prefix}${WORD_BOUNDARY_SUFFIX}`;
|
|
199
|
+
const specifier = `${prefixTokens.join(" ")}${WORD_BOUNDARY_SUFFIX}`;
|
|
213
200
|
if (!specifiers.includes(specifier)) {
|
|
214
201
|
specifiers.push(specifier);
|
|
215
202
|
}
|
|
@@ -217,22 +204,19 @@ export function deriveRules(command, depth = DEFAULT_PREFIX_DEPTH) {
|
|
|
217
204
|
return specifiers;
|
|
218
205
|
}
|
|
219
206
|
/**
|
|
220
|
-
* Match side: fails closed.
|
|
221
|
-
*
|
|
207
|
+
* Match side: fails closed. Each raw subcommand is matched against the specifiers via literal-prefix
|
|
208
|
+
* `matchesSpecifier` (no flag logic on this side). `ALL` (approve) requires every subcommand to
|
|
209
|
+
* match; `ANY` (deny) fires when a single subcommand matches. Empty/unparseable input yields `false`
|
|
210
|
+
* in both modes.
|
|
222
211
|
*/
|
|
223
|
-
export function matchesRules(command, specifiers) {
|
|
212
|
+
export function matchesRules(command, specifiers, mode = SUBCOMMAND_MATCH_MODE.ALL) {
|
|
224
213
|
const subcommands = splitSubcommands(command);
|
|
225
214
|
if (subcommands.length === 0) {
|
|
226
215
|
return false;
|
|
227
216
|
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
if (!specifiers.some((specifier) => matchesSpecifier(subcommand, specifier))) {
|
|
233
|
-
return false;
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
return true;
|
|
217
|
+
const subcommandMatches = (subcommand) => specifiers.some((specifier) => matchesSpecifier(subcommand, specifier));
|
|
218
|
+
return mode === SUBCOMMAND_MATCH_MODE.ANY
|
|
219
|
+
? subcommands.some(subcommandMatches)
|
|
220
|
+
: subcommands.every(subcommandMatches);
|
|
237
221
|
}
|
|
238
222
|
//# sourceMappingURL=command-decomposition.js.map
|
|
@@ -12,20 +12,22 @@ const COMMAND_TOOL_BASE_NAMES = new Set([
|
|
|
12
12
|
CLAUDE_CODE_TOOL.POWER_SHELL.toLowerCase(),
|
|
13
13
|
]);
|
|
14
14
|
/**
|
|
15
|
-
* Whole-tool matching
|
|
16
|
-
*
|
|
17
|
-
*
|
|
15
|
+
* Whole-tool matching: case-insensitive exact tool-name match, plus a trailing `*` (including a bare
|
|
16
|
+
* `*` and MCP prefixes like `mcp__crow-artifacts__*`) as a prefix match. Case-insensitivity aligns
|
|
17
|
+
* with the command strategy (which lowercases the tool name) so a `Bash` rule covers Copilot's
|
|
18
|
+
* `bash`, for both allow and deny.
|
|
18
19
|
*/
|
|
19
20
|
function wholeToolMatches(toolName, rules) {
|
|
21
|
+
const targetTool = toolName.toLowerCase();
|
|
20
22
|
for (const rule of rules) {
|
|
21
23
|
if (rule.specifier !== undefined) {
|
|
22
24
|
continue;
|
|
23
25
|
}
|
|
24
|
-
const pattern = rule.tool;
|
|
25
|
-
if (pattern ===
|
|
26
|
+
const pattern = rule.tool.toLowerCase();
|
|
27
|
+
if (pattern === targetTool) {
|
|
26
28
|
return true;
|
|
27
29
|
}
|
|
28
|
-
if (pattern.endsWith(GLOB_STAR) &&
|
|
30
|
+
if (pattern.endsWith(GLOB_STAR) && targetTool.startsWith(pattern.slice(0, -GLOB_STAR.length))) {
|
|
29
31
|
return true;
|
|
30
32
|
}
|
|
31
33
|
}
|
|
@@ -51,7 +53,7 @@ export const commandRuleStrategy = {
|
|
|
51
53
|
}
|
|
52
54
|
return deriveCommandRules(command).map((specifier) => formatRule({ tool: toolName, specifier }));
|
|
53
55
|
},
|
|
54
|
-
matches: (toolName, input, rules) => {
|
|
56
|
+
matches: (toolName, input, rules, mode) => {
|
|
55
57
|
if (wholeToolMatches(toolName, rules)) {
|
|
56
58
|
return true;
|
|
57
59
|
}
|
|
@@ -66,7 +68,7 @@ export const commandRuleStrategy = {
|
|
|
66
68
|
specifiers.push(rule.specifier);
|
|
67
69
|
}
|
|
68
70
|
}
|
|
69
|
-
return matchesCommandRules(command, specifiers);
|
|
71
|
+
return matchesCommandRules(command, specifiers, mode);
|
|
70
72
|
},
|
|
71
73
|
};
|
|
72
74
|
//# sourceMappingURL=rule-strategies.js.map
|
package/dist/_shared/index.js
CHANGED
|
@@ -24,11 +24,12 @@ export { CreateFragmentAssociationInputSchema, FRAGMENT_KIND, FRAGMENT_FIRST_LEV
|
|
|
24
24
|
export { REFLECTION_AGENT_REF, REFLECTION_TEMP_PREFIX, REFLECTION_OP, ReflectionOpSchema, ReflectionPlanSchema, } from "./schemas/fragment-reflection.schema.js";
|
|
25
25
|
export { MESSAGE_SOURCE_TYPE, MessageSourceSchema, } from "./schemas/message-source.schema.js";
|
|
26
26
|
export { AGENT_COMMAND, AgentCommandSchema } from "./schemas/agent-command.schema.js";
|
|
27
|
-
export { GraphNodeSchema, GraphEdgeSchema, GraphDataSchema, } from "./schemas/graph.schema.js";
|
|
27
|
+
export { GraphNodePositionSchema, GraphNodeSchema, GraphEdgeSchema, GraphDataSchema, } from "./schemas/graph.schema.js";
|
|
28
28
|
export { ConnectorConnectionSchema, ConnectorInfoSchema, ConnectConnectorResponseSchema, } from "./schemas/connector.schema.js";
|
|
29
29
|
export { parseRule, parseRules, formatRule, matchesSpecifier, GLOB_STAR, WORD_BOUNDARY_SUFFIX, PREFIX_STAR_SUFFIX, } from "./auto-approve/rule-format.js";
|
|
30
|
-
export { splitSubcommands, deriveRules, matchesRules,
|
|
30
|
+
export { splitSubcommands, deriveRules, matchesRules, DEFAULT_PREFIX_DEPTH, MAX_DERIVED_RULES, PROCESS_WRAPPERS, SUBCOMMAND_MATCH_MODE, } from "./auto-approve/command-decomposition.js";
|
|
31
31
|
export { defaultRuleStrategy, commandRuleStrategy } from "./auto-approve/rule-strategies.js";
|
|
32
32
|
export { getRuleStrategy } from "./auto-approve/rule-strategy-registry.js";
|
|
33
33
|
export { AutoApproveRuleSet } from "./auto-approve/auto-approve-rule-set.js";
|
|
34
|
+
export { normalizeMcpName } from "./utils/mcp-utils.js";
|
|
34
35
|
//# sourceMappingURL=index.js.map
|
|
@@ -2,6 +2,12 @@ import { z } from "zod";
|
|
|
2
2
|
import { EntityTypeSchema, RelationshipTypeSchema } from "./agent-circle.schema.js";
|
|
3
3
|
import { AGENT_STATUS } from "./agent-runtime-state.schema.js";
|
|
4
4
|
import { FragmentKindSchema } from "./fragment.schema.js";
|
|
5
|
+
/** A user-authored layout position for a graph node; `id` is the node's entity id */
|
|
6
|
+
export const GraphNodePositionSchema = z.object({
|
|
7
|
+
id: z.string(),
|
|
8
|
+
x: z.number(),
|
|
9
|
+
y: z.number(),
|
|
10
|
+
});
|
|
5
11
|
/** A node in the relationship graph — represents an agent, a circle, or a fragment */
|
|
6
12
|
export const GraphNodeSchema = z.object({
|
|
7
13
|
id: z.string(),
|
|
@@ -14,6 +20,8 @@ export const GraphNodeSchema = z.object({
|
|
|
14
20
|
status: z
|
|
15
21
|
.enum([AGENT_STATUS.IDLE, AGENT_STATUS.ACTIVATING, AGENT_STATUS.STREAMING, AGENT_STATUS.COMPACTING])
|
|
16
22
|
.optional(),
|
|
23
|
+
x: z.number().optional(),
|
|
24
|
+
y: z.number().optional(),
|
|
17
25
|
});
|
|
18
26
|
/** An edge in the relationship graph — represents a membership relationship */
|
|
19
27
|
export const GraphEdgeSchema = z.object({
|
package/dist/bootstrap.js
CHANGED
|
@@ -181,7 +181,7 @@ export async function bootstrap(options) {
|
|
|
181
181
|
await registerSensorRoutes(server, sensorManager);
|
|
182
182
|
await registerCircleRoutes(server, circleManager, registry);
|
|
183
183
|
await registerFragmentRoutes(server, fragmentManager, registry);
|
|
184
|
-
await registerGraphRoutes(server, circleManager, registry, runtimeManager, fragmentManager);
|
|
184
|
+
await registerGraphRoutes(server, circleManager, registry, runtimeManager, fragmentManager, relationshipManager);
|
|
185
185
|
await registerFeedRoutes(server, feedManager);
|
|
186
186
|
await registerSystemSettingsRoutes(server, systemSettingsManager);
|
|
187
187
|
await registerConnectorsRoutes(server, connectorManager);
|
package/dist/config/env.js
CHANGED
|
@@ -48,6 +48,7 @@ export const env = {
|
|
|
48
48
|
NODE_ENV: nodeEnv,
|
|
49
49
|
IS_DEV: isDev,
|
|
50
50
|
LOG_LEVEL: getOptional("LOG_LEVEL") ?? (isDev ? "debug" : "info"),
|
|
51
|
+
LOG_PRETTY: getBoolean("LOG_PRETTY"),
|
|
51
52
|
HOST: host,
|
|
52
53
|
PORT: port,
|
|
53
54
|
CORS_ORIGINS: corsOrigins.split(",").map((origin) => origin.trim()),
|
|
@@ -446,8 +446,7 @@ export class SimplyFeedManager extends EventBus {
|
|
|
446
446
|
const feeds = await this.getFeeds();
|
|
447
447
|
for (const feed of feeds) {
|
|
448
448
|
try {
|
|
449
|
-
|
|
450
|
-
log.info({ feedId: feed.id, feedName: feed.title, newItemsCount: items.length }, "Refreshed feed");
|
|
449
|
+
await this.refreshFeed(feed.id, false);
|
|
451
450
|
}
|
|
452
451
|
catch (error) {
|
|
453
452
|
log.error({ feedId: feed.id, feedName: feed.title, error }, "Failed to refresh feed");
|
|
@@ -27,6 +27,9 @@ export function getWriteArtifactToolConfig(agentId, artifactManager, sensorManag
|
|
|
27
27
|
const filename = rawFilename.trim();
|
|
28
28
|
try {
|
|
29
29
|
const isBinary = content_type && content_type !== ARTIFACT_CONTENT_TYPE.TEXT;
|
|
30
|
+
if (!isBinary && !content.trim()) {
|
|
31
|
+
throw new Error("Artifact content must not be empty. Provide content, or use delete_artifact if you meant to remove it.");
|
|
32
|
+
}
|
|
30
33
|
const artifactContent = isBinary ? Buffer.from(content, "base64") : content;
|
|
31
34
|
const metadata = await artifactManager.writeArtifact(agentId, filename, artifactContent, {
|
|
32
35
|
type,
|
|
@@ -31,6 +31,9 @@ export function getWriteCircleArtifactToolConfig(agentId, artifactManager, senso
|
|
|
31
31
|
const filename = rawFilename.trim();
|
|
32
32
|
try {
|
|
33
33
|
const isBinary = content_type && content_type !== ARTIFACT_CONTENT_TYPE.TEXT;
|
|
34
|
+
if (!isBinary && !content.trim()) {
|
|
35
|
+
throw new Error("Artifact content must not be empty. Provide content, or use delete_circle_artifact if you meant to remove it.");
|
|
36
|
+
}
|
|
34
37
|
const artifactContent = isBinary ? Buffer.from(content, "base64") : content;
|
|
35
38
|
const metadata = await artifactManager.writeCircleArtifact(circle_id, filename, artifactContent, {
|
|
36
39
|
type,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { McpServerConfigSchema, CreateMcpConfigInputSchema, UpdateMcpConfigInputSchema, MCP_CONFIG_TYPE, CROW_SYSTEM_AGENT_ID, AGENT_TYPE, } from "../_shared/index.js";
|
|
1
|
+
import { McpServerConfigSchema, CreateMcpConfigInputSchema, UpdateMcpConfigInputSchema, MCP_CONFIG_TYPE, CROW_SYSTEM_AGENT_ID, AGENT_TYPE, normalizeMcpName, } from "../_shared/index.js";
|
|
2
2
|
import { logger } from "../utils/logger.js";
|
|
3
3
|
import { AppError } from "../core/error/app-error.js";
|
|
4
4
|
import { APP_ERROR_CODES } from "../core/error/app-error.types.js";
|
|
@@ -79,7 +79,7 @@ export class CrowMcpManager {
|
|
|
79
79
|
return (isCrowSystemAgent(agentId) && config.enableForCrow) || configuredMcpIds.has(config.id);
|
|
80
80
|
});
|
|
81
81
|
for (const config of userMcpConfigs) {
|
|
82
|
-
const name =
|
|
82
|
+
const name = normalizeMcpName(config.name);
|
|
83
83
|
if (serverConfigMap.has(name)) {
|
|
84
84
|
log.warn({ configId: config.id, name }, "User MCP config name collides with an internal server, skipping");
|
|
85
85
|
continue;
|
|
@@ -194,9 +194,6 @@ export class CrowMcpManager {
|
|
|
194
194
|
await this.store.delete(MCP_CONFIG_STORE_TABLE, configId);
|
|
195
195
|
log.info({ configId, name: existing.name }, "MCP config deleted");
|
|
196
196
|
}
|
|
197
|
-
normalizeMcpName(name) {
|
|
198
|
-
return name.toLowerCase().replaceAll(" ", "_");
|
|
199
|
-
}
|
|
200
197
|
/** Map a persisted user MCP config to a Crow MCP transport. */
|
|
201
198
|
toTransport(config) {
|
|
202
199
|
if (config.type === MCP_CONFIG_TYPE.STDIO) {
|