Skip to content

v2026.05.19#291

Merged
xiami762 merged 86 commits into
mainfrom
dev
May 19, 2026
Merged

v2026.05.19#291
xiami762 merged 86 commits into
mainfrom
dev

Conversation

@stephamie7
Copy link
Copy Markdown
Contributor

No description provided.

duguwanglong and others added 30 commits May 8, 2026 16:00
基于 aisoc_mini 的告警去重算法(URI 归一化 + 5-gram Shingling + Jaccard
相似度)移植为 flocks 工作流,包含 5 个线性节点:接收解析 → URI 归一化
→ 去重键计算 → 分组去重 → 报告生成。支持严格字段精确匹配与 LSH 字段近似
匹配,输出唯一告警、重复告警及 Markdown 分析报告。

Co-authored-by: Cursor <cursoragent@cursor.com>
…stages)

重写工作流以完整对齐 aisoc_mini 的 LogProcessPipeline 四阶段主流程:
- normalize_logs: TDP/Skyeye 字段映射 + 嵌套结构扁平化
- filter_logs: jsonLogic 规则过滤(扫描类/出站/非HTTP告警剔除)
- dedup_logs: URI 归一化 + 5-gram Jaccard 相似度去重,生成 dedup_key
- analyze_unique: 仅对唯一 dedup_key 调用 LLM is_attack 研判并回填重复告警
- generate_report: 输出四阶段统计 Markdown 报告及 JSONL 数据文件

Co-authored-by: Cursor <cursoragent@cursor.com>
…rallelize LLM analysis

修复审阅中发现的功能性偏差:

1. filter_logs: 完整对齐 LogFilter._get_tdp_process_type() 9 种 process_type 分类
   - 修正:HTTP 非扫描告警无论方向(in/out/lateral)都需研判(之前错误地只保留
     direction=in/none,会丢失大量本应分析的出站/横向 HTTP 告警)
   - HTTP 协议判断兼容 application_layer_protocol/net_type/net_app_proto 多字段
   - threat_type 取值与原版一致:tdp 取 threat_name,skyeye 取 threat_type
   - 新增 _process_type、_need_analysis_attack_status 字段
   - 统计中加入 filter_process_type_counts

2. analyze_unique: ThreadPoolExecutor 并行调用 LLM(与 LogAnalysis.process_parallel
   一致,可通过 analyze_max_workers 配置),单条失败不影响其他

3. dedup_logs: 移除函数体内重复的 import hashlib as _hl

4. 各节点新增轻量 print 进度日志,便于大批量调试

5. workflow.md 同步修正过滤逻辑描述

Co-authored-by: Cursor <cursoragent@cursor.com>
…result routing

用显式 branch 节点替换代码内部的 if-else 路由,拓扑结构变为:

  receive_alerts
      → branch_log_type (select_key: source_log_type)
          label:"tdp"    → normalize_tdp    → filter_logs
          label:"skyeye" → normalize_skyeye → filter_logs
      → branch_has_alerts (select_key: _has_alerts)
          label:"true"  → dedup_logs → analyze_unique → generate_report
          label:"false" → generate_empty_report(无 LLM 调用的快速终点)

修复:
  - branch_log_type 两条边均使用显式 label ("tdp"/"skyeye"),
    使 lint 正确识别为互斥路径,消除 multi_incoming_no_join 报错
  - false 分支独立终结于 generate_empty_report,
    避免 generate_report 多入边 lint 错误
  - 测试验证:TDP/Skyeye 字段映射、has_alerts true/false 四条路径均正确路由

Co-authored-by: Cursor <cursoragent@cursor.com>
…y to dedup-only

- 目录重命名 alert_dedup → network_alert_dedup
- workflow.json / meta.json name & id 改为 network_alert_dedup
- 移除 analyze_unique / generate_report / generate_empty_report / branch_has_alerts 四个节点
- 移除 LLM 研判相关参数(analyze_enabled / analyze_max_workers)
- dedup_logs 成为终点节点,直接输出 dict:
    deduped_alerts(全量含 dedup_key)/ unique_alerts(唯一簇)/ stats / dedup_summary
- filter_logs 清理预填空结果逻辑,精简 outputs 传递
- workflow.md 更新为三阶段流程说明(归一化→过滤→去重)
- lint 无警告,模型验证通过

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…ert_dedup

- filter_logs 新增 _has_alerts 输出
- 插入 branch_has_alerts 分支节点(select_key: _has_alerts)
- true 路径 → dedup_logs(执行去重,终点)
- false 路径 → dedup_empty(无告警,直接返回空 dict,终点)
- 更新 workflow.md 流程图及节点说明
- lint 无警告,模型验证通过(8 节点 / 8 边)

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…p_alert_dedup

filter_logs 直接连接 dedup_logs,dedup_logs 自然处理空列表输入

Co-authored-by: Cursor <cursoragent@cursor.com>
…_logs

使用 datasketch MinHash + MinHashLSH 替换原有 O(n²) 暴力 Jaccard:
- NUM_PERM=128, MINHASH_SEED=2024(对齐 lsh_processor.py)
- 共享 permutations,对齐 LSHProcessor 初始化方式
- query_most_similar:LSH 快速候选 → 精确 Jaccard 取最相似(对齐原版逻辑)
- normalize_uri 对齐 utils.py(DATETIME/UUID/TRAVERSAL/NULL_REPLACED/HEXADECIMAL)
- dedup_key = MD5(strict_text + '. ' + lsh_key),对齐 LogDedup._generate_dedup_key_text
- 实测 453 条 TDP 过滤后告警 → 360 个唯一簇,压缩率 20.5%

Co-authored-by: Cursor <cursoragent@cursor.com>
…dup_logs

- All Chinese comments replaced with English
- cluster_id (int) written to alert['_lsh_cluster_id'] so callers can inspect LSH cluster membership
- lsh_cache now stores MinHash directly (not wrapped in dict) for cleaner re-ranking
- summary string switched to English

Co-authored-by: Cursor <cursoragent@cursor.com>
LSH state (lsh_index + lsh_cache) is now saved to and loaded from:
  ~/.flocks/data/workflows/http_alert_dedup/lsh_state_np128_th<threshold>.pkl

- get_lsh_state_path(): builds path via Config().get_data_path()
- load_lsh_state(): loads pickle, validates num_perm/threshold params match
- dump_lsh_state(): saves after each run; mirrors LogDedup.dump()
- Filename encodes NUM_PERM and threshold so param changes auto-reset state
- stats gains lsh_total_clusters and lsh_state_path fields
- Verified: run2 correctly loads run1 clusters and accumulates new ones

Co-authored-by: Cursor <cursoragent@cursor.com>
Four correctness fixes plus the datasketch dependency:

1. Persist dedup_key_cache (the set of MD5 keys ever seen) into the same pkl
   so that 'dedup_key_already_exists' is correct across restarts and batches.
   Previously it was a per-run local set, breaking cross-batch dedup detection.

2. Atomic write: pickle to <state>.tmp, fsync, then os.replace() over the
   target. A crash mid-write no longer corrupts the persisted state.

3. fcntl.flock(LOCK_EX) on a sibling .lock file serializes load+modify+dump
   across concurrent workflow runs, eliminating the read-modify-write race
   that previously caused lost updates.

4. dedup_enabled=False branch now sets _lsh_cluster_id=None so that downstream
   consumers see a consistent schema regardless of dedup mode. In-batch
   duplicate detection still works in this branch.

Also: warn when persisted cluster count exceeds 100k so operators can rotate
state. New stat: lsh_total_dedup_keys.

Verified end-to-end:
  - cross-batch: same alert in run2 reports already_exists=True
  - corruption:  garbage pkl is auto-discarded, no crash
  - concurrent:  5 parallel processes writing 10 alerts each end up with
                 50 persisted clusters (not lost to read-modify-write)
  - disabled:    _lsh_cluster_id=None, in-batch duplicate detected

Co-authored-by: Cursor <cursoragent@cursor.com>
Cross-platform support:
- Replace bare 'import fcntl' with platform detection.
- POSIX path keeps fcntl.flock(LOCK_EX).
- Windows path uses msvcrt.locking(LK_LOCK, 1) on a single byte of the lock
  file, looping on OSError to wait beyond LK_LOCK's built-in 10-second cap.
- Both branches release the lock symmetrically in release_lock().

Review fixes:
- 'lsh_state_path', 'lsh_total_clusters', 'lsh_total_dedup_keys' are no longer
  written to stats when dedup_enabled=False (was misleading; no file is touched
  in that mode). Added 'dedup_state_persisted' bool for callers to branch on.
- Cluster-overflow warning now also checks dedup_key_cache, since pkl size is
  dominated by per-key entries, not per-cluster.
- normalize_uri's UUID regex now uses re.IGNORECASE so uppercase UUIDs map to
  the same 'UUID' placeholder (and thus the same LSH cluster) as lowercase ones.
- Disabled-mode summary clearly states 'no state persisted, in-batch only'.

Verified: cross-batch, disabled-mode stats, uppercase UUID dedup, concurrent writers.
Co-authored-by: Cursor <cursoragent@cursor.com>
…; add alert_file support

run_workflow.py:
- When workflow is a JSON-decoded non-dict (e.g. the AI wraps the path in extra
  quotes producing '\"..path..\"'), treat the decoded string as a file path instead
  of crashing with 'str object has no attribute name'.
- Add upfront dict sanity-check: if the dict has no 'start' key it's almost certainly
  the inputs dict passed to the wrong parameter; return a clear error instead of a
  Pydantic validation traceback.
- Add a comment clarifying that the else-branch delivers a Path, not a str.

workflow.py:
- Add sync_workflows_from_filesystem() which app.py imports at startup.
  Triggers the one-time storage→filesystem migration then returns the count of
  discovered workflows so the startup log entry is informative.

http_alert_dedup/workflow.json:
- receive_alerts now accepts alert_file (absolute or ~-prefixed path to a JSON file)
  as an alternative to inlining the alerts list directly in inputs.
  This removes the need to manually load large log files via bash before running the
  workflow (the main friction observed in session 询问可用工作流).
- sampleInputs annotated with a _comment_alert_file hint.

Co-authored-by: Cursor <cursoragent@cursor.com>
…type errors

Previous fix used 'parsed if isinstance(parsed, str) else raw' which silently
passed list/int/bool results to Path(), giving a misleading 'file not found' error.

Now three explicit branches:
- parsed is str  → double-encoded path; use decoded value as file path
- parsed is None → JSONDecodeError; use raw string as file path (original behaviour)
- parsed is other → clear error stating the unexpected JSON type

Co-authored-by: Cursor <cursoragent@cursor.com>
…ID lookup

Resolve the merge conflict in the `workflow` string parsing block by
combining both sides:

- HEAD: explicit type dispatch on json.loads() result (dict / str / None /
  other) with clear per-type error messages.
- Upstream (d8b44e5): on JSONDecodeError, try read_workflow_from_fs() first
  so callers can pass a plain workflow ID instead of a full JSON string.

Merged result: keep the type-dispatch structure from HEAD; in the
`parsed is None` (JSONDecodeError) branch, attempt workflow-ID resolution
via read_workflow_from_fs() before falling back to a file path.

Co-authored-by: Cursor <cursoragent@cursor.com>
The get_state_paths() change to ~/.flocks/workspace/workflows/ was lost
when merging dev into feat/alert-dedup-workflow (da58f7b). Re-apply:

- Remove top-level `from flocks.config import Config` import
- Replace Config().get_data_path() with
  Config().get_global().data_dir.parent / 'workspace' / 'workflows'
- Update node description accordingly

Also sync the running release snapshot and restart the service process
so the /invoke API immediately uses the new path.

Co-authored-by: Cursor <cursoragent@cursor.com>
…calls

workflow_center_invoke (POST /workflow-center/{id}/invoke) now records
execution stats via create_execution_record + _update_workflow_stats +
_record_execution_result, so that UI callCount / successCount / errorCount
counters are updated for every /workflow-center call — not only for
agent-driven /workflow/{id}/run calls.

Co-authored-by: Cursor <cursoragent@cursor.com>
New workflow:
- Add alert_dedup_triage workflow: chains http_alert_dedup → tdp_alert_triage
  in a single pipeline; per-alert dedup via MinHash LSH, then LLM triage for
  first-seen unique alerts; duplicate alerts are annotated with cached triage
  results from a persisted triage_cache.pkl (FIFO LRU, max_dedup_keys cap).

http_alert_dedup improvements:
- Upgrade dedup_key_cache from set to ordered dict for FIFO LRU eviction.
- Add max_dedup_keys input param (default 100 000); oldest entries are evicted
  before each persist so the state file stays bounded.
- Use a monotonic cluster_id counter (_cid_box) instead of len(lsh_cache) so
  IDs never collide after eviction; remove evicted cluster_ids from the
  MinHashLSH index to prevent stale query results.
- Expose lsh_max_dedup_keys / lsh_evicted_keys / lsh_evicted_clusters in stats.
- Forward max_dedup_keys through normalize_* and filter_logs nodes.

tdp_alert_triage:
- Remove web-log detection branch; workflow now accepts HTTP alerts directly.
- Add _strip_think() to all LLM nodes to strip <think>…</think> blocks.
- Update workflow.md to reflect simplified node structure.

Test tools (moved from scripts/ → tests/integration/):
- test_http_alert_dedup_stream.py: streaming simulation for http_alert_dedup.
- test_alert_dedup_triage_stream.py: end-to-end dedup → triage pipeline test.

Co-authored-by: Cursor <cursoragent@cursor.com>
- Add flocks/syslog package (constants, parser, listener, manager) to
  receive UDP/TCP syslog messages and trigger workflow execution via the
  Channel-GatewayManager pattern
- Expose POST/GET /workflow/{id}/syslog-config API endpoints; start/stop
  all enabled listeners in the FastAPI lifespan
- Add SyslogConfig TS interface and saveSyslogConfig/getSyslogConfig API
  methods to the frontend workflow client
- Extract PublishSection, KafkaSection, SyslogSection from RunTab into a
  new IntegrationTab component; wire it as a fourth "Integration" tab in
  RightPanel so the Run tab only shows test-run and execution history
- Add tabIntegration i18n keys (zh-CN / en-US) and syslogActive badge
  shown when listener is enabled and collapsed

Co-authored-by: Cursor <cursoragent@cursor.com>
Group data-ingestion triggers under a shared flocks/ingest/ namespace so
that future connectors (kafka, webhook, …) live alongside syslog as
sibling sub-packages rather than top-level packages.

- Move flocks/syslog/* → flocks/ingest/syslog/*
- Add flocks/ingest/__init__.py (empty package marker)
- Update all internal imports (flocks.syslog → flocks.ingest.syslog)
  in listener.py, manager.py, __init__.py, server/app.py and
  server/routes/workflow.py

Co-authored-by: Cursor <cursoragent@cursor.com>
receive_alerts node now handles three input sources in priority order:
1. syslog_message (injected by flocks syslog listener, RFC3164/5424)
   - TDP alert JSON parsed from syslog_message.message
   - Syslog metadata (hostname, severity, timestamp…) attached to alert
     under _syslog_meta for traceability; does not affect dedup/triage logic
2. alerts (batch list, existing)
3. alert_file (local JSON path, existing)

Also adds syslog-config API documentation and example to workflow.md and
syslog_message sample to metadata.sampleInputs.

Co-authored-by: Cursor <cursoragent@cursor.com>
…move HTTP service dependency

Replace direct HTTP POST calls to published service ports (19000/19001)
with in-process embedded invocations using flocks.workflow.runner.run_workflow
and flocks.workflow.fs_store.workflow_scan_dirs.

- _invoke_workflow(): locates sub-workflow.json via workflow_scan_dirs(),
  then calls run_workflow() directly in the same process
- Removes urllib/HTTP helpers, dedup_service_url, triage_service_url inputs
- Adds dedup_workflow_id / triage_workflow_id inputs (default: http_alert_dedup,
  tdp_alert_triage) so callers can override the sub-workflow IDs if needed
- http_alert_dedup and tdp_alert_triage no longer need to be published as
  running services for alert_dedup_triage to function

Co-authored-by: Cursor <cursoragent@cursor.com>
…nglish

- Node description fields: translated to English
- generate_summary: verdict_label / stage_label dicts and summary_md
  template converted from Chinese to English
- Code comments in receive_alerts and dedup_and_triage were already English
- description_cn field and LLM prompt content in tdp_alert_triage left as-is
  (intentionally Chinese for LLM interaction)

Co-authored-by: Cursor <cursoragent@cursor.com>
…able

Co-authored-by: Cursor <cursoragent@cursor.com>
…report in batch mode

Add branch_output_mode node after dedup_and_triage:
- input_mode == 'syslog' -> direct_output: returns single-alert triage
  result directly (one-liner summary_report, no table, no file write)
- input_mode == 'alerts' | 'alert_file' -> generate_summary: full
  statistics table + top-risk report written to pipeline_summary.md

Both paths emit identical output field names for downstream compatibility.

Co-authored-by: Cursor <cursoragent@cursor.com>
…iggered runs

Syslog-triggered workflow runs were invisible in the WebUI history panel and
not counted in the workflow stats card because `_trigger_workflow` called the
runner directly, bypassing both the execution record write and the call counter
update. Run records were never written, and `callCount` only ever reflected
HTTP-triggered runs.

This change makes the syslog path go through the same persistence helpers as
the HTTP API path so all trigger sources are uniformly visible in the UI:

- syslog/manager: wrap each run with create_execution_record /
  record_execution_result; write the same fields the WebUI consumes
  (`outputResults`, `errorMessage`, `duration`, `executionLog`, `currentNodeId`,
  `currentPhase`, `currentStepIndex`); tag input params with `_trigger=syslog`
  for source identification.
- workflow/execution_store: move the workflow stats counter update into
  `record_execution_result` so every persisted result automatically increments
  callCount/successCount/errorCount/totalRuntime/avgRuntime, regardless of
  trigger source.
- server/routes/workflow: remove the now-redundant `_update_workflow_stats`
  calls from the HTTP run/invoke paths and drop the orphaned helper to avoid
  double counting.

Co-authored-by: Cursor <cursoragent@cursor.com>
… triage

http_alert_dedup:
- Replace branch_log_type + normalize_tdp + normalize_skyeye nodes with a
  single unified normalize node; each alert is individually classified via
  field signatures (nested net dict / behave_uuid for TDP; uri / vuln_name /
  attack_result for Skyeye) before field mapping, enabling mixed-type batches
  in a single invocation.
- Update filter_logs to read per-alert _source_type set by normalize instead
  of the batch-level source_log_type, ensuring correct threat/process type
  classification in mixed batches.
- source_log_type is retained as an optional batch-level fallback hint when
  per-alert detection is inconclusive.

alert_dedup_triage:
- Implement 4-priority source_log_type resolution in receive_alerts:
  (1) explicit input param, (2) syslog app_name/hostname hint,
  (3) JSON field auto-detection on first alert, (4) default 'tdp'.
- Emit source_log_type_reason for traceability.

tdp_alert_triage:
- Extend receive_alert pick() lookups to cover flat TDP field names
  (net_real_src_ip, net_dest_ip, net_http_url, net_http_reqs_body,
  net_http_resp_body, net_http_status, etc.) alongside nested TDP and
  normalized schema, fixing empty-payload LLM analysis for pre-flattened
  TDP alerts arriving via alert_dedup_triage.

Co-authored-by: Cursor <cursoragent@cursor.com>
duguwanglong and others added 23 commits May 14, 2026 19:08
…lert_dedup

Root causes identified:
1. Large alert lists (enriched_alerts, unique_alerts, …) were written
   verbatim into every workflow_execution SQLite row — both in
   outputResults and in each executionLog snapshot emitted by
   _on_step_complete — duplicating megabytes of data that is already
   persisted to JSONL on disk.
2. The problem affected both the syslog trigger path (manager.py) and
   the HTTP background execution path (routes/workflow.py), but only the
   former had a local fix applied; the HTTP path was left unprotected.

Changes:
- execution_store.py: add compact_outputs_for_storage() and
  compact_history_for_storage() as the canonical compact API.
  Lists whose key belongs to DEFAULT_LARGE_LIST_KEYS and whose length
  exceeds DEFAULT_COMPACT_SIZE_THRESHOLD (100) are replaced with a
  lightweight _<key>_count integer; small lists and unknown keys pass
  through unchanged, so ordinary metadata arrays are never silently
  dropped.
- syslog/manager.py: remove the local _compact_outputs/_compact_history
  implementation and import the shared helpers from execution_store.
- routes/workflow.py: apply compact_outputs_for_storage to outputResults
  and compact_history_for_storage to executionLog in both the background
  execution path and the workflow-center invoke path.  Also compact each
  step dict inside _on_step_complete before appending to step_history so
  that every intermediate _write_progress snapshot stays bounded.
- tests/workflow/test_execution_store_compact.py: 14 new unit tests
  covering the size-threshold guard, non-mutation contract, defensive
  pass-through for non-dict inputs, and the end-to-end size reduction
  (>1 000x on a 10K-alert payload).

Co-authored-by: Cursor <cursoragent@cursor.com>
inputParams was written verbatim into every workflow_execution SQLite row.
For HTTP /run batch calls that pass a large alert list as an input
parameter (e.g. {"raw_alerts": [...10k items...]}) this inflates each row
by the same order of magnitude as the uncompacted outputResults bug fixed
in the previous commit.

Changes:
- execution_store.py: create_execution_record() now passes input_params
  through compact_outputs_for_storage() before building the record, so
  known large-list keys (raw_alerts, enriched_alerts, etc.) are replaced
  with lightweight _<key>_count integers.  Scalar fields and unknown keys
  are preserved unchanged, so audit / replay use-cases are not affected.
- tests/workflow/test_execution_store_compact.py: two new tests pin the
  expected behaviour — "alerts" (not in DEFAULT_LARGE_LIST_KEYS) passes
  through unchanged, while "raw_alerts" (in the default set) is compacted.

Co-authored-by: Cursor <cursoragent@cursor.com>
…274)

When nvm activates a supported Node version but `node` on PATH remains older,
pin NODE_CMD/NPM_CMD/NPX_CMD to NVM_BIN for the rest of the installer run.
Adds a Linux integration test for the stale-resolution scenario.
Five issues raised in code review, all fixed in this commit:

1. Docstring/behaviour mismatch — alerts key
   create_execution_record()'s docstring previously used {"alerts":[…10k]}
   as the example of what gets compacted.  "alerts" is NOT in
   DEFAULT_LARGE_LIST_KEYS, so the row would silently stay large.  The
   docstring now cites "raw_alerts" (which IS in the set) and adds an
   explicit note that keys outside the default set are stored verbatim.
   compact_outputs_for_storage() gains the same clarification so callers
   can easily see the full list of compacted keys.

2. workflow_center_invoke — executionLog path
   The invoke path proxies to an external service and never populates
   executionLog locally, so no data was at risk.  Added an explanatory
   comment and an explicit compact_history_for_storage() call on the
   executionLog field as a forward-compatible guard against future code
   that might populate it before the final write.

3. tuple sequences not compacted
   compact_outputs_for_storage() checked isinstance(v, list), missing
   tuple values that some serialisation paths may produce.  Changed to
   isinstance(v, (list, tuple)).  New test test_compact_outputs_compacts_
   tuple_sequences() pins this behaviour.

4. Unused import pytest
   Removed the bare "import pytest" from test_execution_store_compact.py;
   no pytest.raises / @pytest.mark usages exist in the file.

5. Observability note
   compact_outputs_for_storage() docstring now explicitly states that
   compacted keys are replaced with _<key>_count and that callers who
   need the full list contents must read from the JSONL files written by
   the workflow.

Co-authored-by: Cursor <cursoragent@cursor.com>
…y-leak

fix/stream alert dedup memory leak
Follow-up to PR #267: the syslog config form already validated host but
accepted any integer for port, allowing values such as 0, 22, or 99999
to be saved and only blow up at bind time with a confusing OS error
(e.g. "[Errno 49] can't assign requested address").

- Backend SyslogConfigRequest.port now enforces ge=1, le=65535 via
  Pydantic so out-of-range ports are rejected with HTTP 422 before the
  config is persisted or the listener is restarted.
- IntegrationTab.tsx adds an inline validator that strictly matches a
  numeric string (rejecting "5140abc", "3.14", "-1", etc.) and the
  1..65535 range; the input shows a red border with a localized hint
  and the save button is disabled while the value is invalid.
- extractErrorMessage now flattens Pydantic 422 detail arrays
  ([{loc, msg, type}, ...]) into a readable "; "-joined string so
  scripted callers (or any caller that bypasses the UI validator)
  see the actual validation message instead of "[object Object]".
- Adds zh-CN/en-US copy for detail.run.syslogPortError.

Co-authored-by: Cursor <cursoragent@cursor.com>
…tion

fix(syslog): validate listener port range on save
Move sangfor-edr-use and sangfor-xdr-use from docs/ into the standard
skills directory (.flocks/plugins/skills/).

Changes made during review:

- edr: remove incorrect API mode section; EDR has no open API,
  all operations must go through browser/CDP
- xdr: fix wrong script name in pitfalls table (cdp_fetch.py ->
  fetch_xdr_system_state.py)
- xdr: fix API vs CDP comparison table — system state row had CDP
  script listed under API column, now shows ❌
- xdr: fix ambiguous "request confirmation" wording; now clearly
  states API is default and fallback to browser only on failure
- both: replace hardcoded Windows absolute paths in execution examples
  with cross-platform placeholders (<FLOCKS_VENV> / <FLOCKS_PLUGINS>),
  and add macOS/Linux parallel examples
- both: use tempfile.gettempdir() for daemon port file path instead of
  hardcoded C:/Users/Administrator/AppData/Local/Temp
- both: add macOS/Linux Chrome/Edge remote debugging start commands
- xdr: rename dict key data接入 -> data_ingestion to avoid mixed
  Chinese/English key names
- both: move inline `import re` to module top level

Co-authored-by: Cursor <cursoragent@cursor.com>
feat(skills): add sangfor-edr-use and sangfor-xdr-use skills
…275)

* feat(task): enforce five-field cron and format times in schedule TZ

Reject unsupported six-field Quartz expressions with a clear hint; show
CLI and task center datetimes in the scheduler timezone for readability.

* fix(task): skip plugin task specs with invalid cron fields

Validate cron during plugin upsert; log and skip bad specs so six-field
Quartz expressions cannot create or overwrite schedulers.

* fix(task): validate cron with croniter and avoid trigger mutation

Deep-copy triggers on scheduler create; keep existing cron when switching
to run-once without a new cron. Reject invalid five-field expressions via
croniter; clarify unknown timezone labels in task datetime formatting;
mark plugin spec upserts as fully skipped on bad cron.
* refactor(session): modular system prompts and runner wiring

- Extend prompt composition (provider blocks, guidance, caching) and
  consolidate defaults; trim redundant static template bodies.
- Update prompt_strings, Rex/Hephaestus builders, prompt_utils, and memory
  bootstrap for the new prompt pipeline.
- Adjust session runner for Anthropic-style system blocks and related
  message handling.
- Refresh session/agent/memory/integration tests; add Anthropic system
  blocks unit coverage.

* refactor(rex): streamline prompt builder; ship flocks_mcp in core

- Relocate flocks_mcp from ~/.flocks plugin path to flocks/tool/system.
- Rex prompt_builder and agent.yaml/toolset updates; agent_factory hooks.
- Session prompt/runner and prompt_strings tweaks; registry and skill wiring.
- Refresh AGENTS.md; extend tests for factory, runner, toolset, builtins.

* fix(session): reorder system prompt blocks; keep lsp tool non-native

- Move agent_identity and tool_catalog layers for clearer guidance order.
- Exclude lsp from bulk native=True classification in ToolRegistry.
- Minor lsp_tool tweak; extend runner and builtin management tests.

* refactor(session): trim prompt strings; tighten bash tool copy

- Remove redundant prompt.py / prompt_strings content where duplicated.
- Refine bash tool description (dedicated-tool bullets and usage notes).
- Align prompt_tokens, runner_step, and bash registry tests.

* refactor: remove file search, list, codesearch, and omo tools

- Remove Python/TUI tool implementations and registry/catalog wiring
- Update agent YAMLs, skills docs, and validator for tool-builder
- Adjust session runner, prompts, and OpenAI responses tool prep
- Add TUI question-state module with tests; update DelegateTaskCard

* refactor: unify general session prompt, remove batch tool

- Add general.txt prompt and get_prompt_general; drop Python qwen.txt
- Remove batch tool from Python/TUI registries and delegate_task paths
- Update Rex/hephaestus prompt builders, prompt_utils, and session assembly
- Refresh anthropic prompts; add TUI prompt-source and system test

* refactor(plan): remove plan agent yaml; simplify plan_exit

- Drop bundled plan agent definition; keep plan_enter/plan_exit tools
- Exit plan mode without confirmation; pass call_id for question context
- Align TUI plan tool copy; extend test_tools coverage

* refactor(session): hook payloads, task scheduling, and file tools

Rework runner/hooks pipeline for LLM hook payloads, replace legacy task_center
with schedule_task_center, remove multiedit end-to-end, add path_utils and a
minimax prompt fragment, and align file tools, TUI, and tests.

* refactor(session): message parts, todo flow, and runner loop

Extend assistant message handling, rework todo tool/session/TUI wiring with
runner and session_loop, adjust compaction policy and provider SDK hooks, and
add regression tests (including DeepSeek provider).
* refactor(tool): split bash descriptions and require PowerShell on Windows

Unix and Windows now get tailored bash-tool copy; Windows drops cmd
fallback, surfaces missing PowerShell clearly, and documents PS 5.1
quirks only when using powershell.exe.

* fix(tool): escape Windows path examples in bash tool description

Use doubled backslashes in the PowerShell description so the rendered
guidance shows valid Windows-style paths.

* feat(session): require replies in the user's language

Add a consistent language-matching rule to Rex prompt XML and the
general, Anthropic, and MiniMax session prompt templates.
Prefer single-line semicolon-separated -c snippets on Windows PowerShell
to avoid quoting/newline pitfalls; document in browser-use, cdp-direct, and web2cli.
…280)

Prevent nested workflow tools from overwriting run_workflow metadata,
report completed status for successful task/delegate results, reject
stale running updates over terminal tool parts, and tighten delegate
card rendering so run_workflow is not misclassified.
…ifespan (#279)

* fix(mcp): thread-safe commands across event loops for workflow runtime

Route MCP client commands through the owner loop, initialize MCP in the
workflow service lifespan, and add regression tests for cross-loop usage
and route/service behavior.

* fix(mcp,workflow): harden disconnect during connect and surface MCP readiness

Only enqueue disconnect when connected; expose mcp_ready in workflow service
health and return 503 when MCP init fails; add regression tests.

* feat(api): reconnect MCP after update when server was connected

Return reconnected/reconnect_error in the update response; bound reconnect
with timeout derived from server config; extend route tests.
Merge the open detail snapshot into the visible list, poll execution by id
while the drawer is open, and enable SessionChat live streaming whenever a
session id exists so completed/running transitions stay accurate.
…#283)

Replace per-message message_shapes with aggregate message_summary for
each chat/stream request, and move plugin, tool, session, and compaction
noise from INFO to DEBUG so long runs stay readable.
…metadata (#284)

Pass only a registered clear callback into slash commands so /clear still
emits the fallback message on WebUI. Document the resolved memory root and
arbitrary daily note paths; surface model/provider in runtime metadata; align
tool copy and tests.
Load Storage-backed custom agents during registry initialization so agents created through /api/agent survive service restarts.
* fix(feishu): init legacy WS client on worker loop and improve shutdown

Defer lark_oapi Client construction to the background thread's event loop
to avoid "attached to a different loop" errors. Track ping/receive tasks
and reset state on stop so restart is reliable.

* fix(feishu): handle stop during legacy WS client initialization

Wait for worker-thread client init before stop proceeds; skip start when
stop is requested early. Guard coroutine scheduling when loop is not running.
…hema (#287)

* refactor(command): unify slash direct handlers and agent-safe tool schema

Extract shared direct command execution and help formatting so the UI
handler, run_slash_command tool, and Rex guidance stay consistent. Limit
the agent tool to read-only direct commands and improve /help formatting.

* feat(command,webui): add /agents command and refresh catalogs on focus

Expose /agents as a shared direct slash command for UI and agent tools.
WebUI agents/tools/skills/workflows pages refresh when the tab regains
focus; Session restores the last selected chat from localStorage. Add
skill-builder skill and route SkillSheet creation through it.
Prevent bash commands and large tool inputs from expanding the tool card
summary; cap input JSON preview height and keep full values on hover.
…o-v2026.5.19

chore: update version to v2026.5.19 in pyproject.toml and uv.lock
xiami762 and others added 3 commits May 19, 2026 17:56
Use _provider.yaml location to distinguish project vs user plugins for
delete protection, avoiding false positives from stale native flags.

Co-authored-by: Cursor <cursoragent@cursor.com>
…escriptor-path

fix(provider): classify API builtin status from descriptor path
@xiami762 xiami762 merged commit bfad773 into main May 19, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants