nextcloud-agent 2.3.2__tar.gz → 2.3.4__tar.gz
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.
- {nextcloud_agent-2.3.2 → nextcloud_agent-2.3.4}/PKG-INFO +9 -15
- {nextcloud_agent-2.3.2 → nextcloud_agent-2.3.4}/README.md +6 -8
- nextcloud_agent-2.3.4/nextcloud_agent/__init__.py +11 -0
- nextcloud_agent-2.3.4/nextcloud_agent/__main__.py +4 -0
- nextcloud_agent-2.3.4/nextcloud_agent/connector_sources.py +82 -0
- {nextcloud_agent-2.3.2 → nextcloud_agent-2.3.4}/nextcloud_agent/kg_ingest.py +5 -59
- {nextcloud_agent-2.3.2 → nextcloud_agent-2.3.4}/nextcloud_agent/mcp_server.py +0 -68
- {nextcloud_agent-2.3.2 → nextcloud_agent-2.3.4}/nextcloud_agent/ontology/certification.json +6 -9
- {nextcloud_agent-2.3.2 → nextcloud_agent-2.3.4}/nextcloud_agent/ontology/mappings/source.yaml +1 -1
- {nextcloud_agent-2.3.2 → nextcloud_agent-2.3.4}/nextcloud_agent/ontology/nextcloud.ttl +10 -11
- {nextcloud_agent-2.3.2 → nextcloud_agent-2.3.4}/nextcloud_agent/prompts/file_steward.json +0 -2
- {nextcloud_agent-2.3.2 → nextcloud_agent-2.3.4}/nextcloud_agent.egg-info/PKG-INFO +9 -15
- {nextcloud_agent-2.3.2 → nextcloud_agent-2.3.4}/nextcloud_agent.egg-info/SOURCES.txt +1 -9
- nextcloud_agent-2.3.4/nextcloud_agent.egg-info/entry_points.txt +8 -0
- {nextcloud_agent-2.3.2 → nextcloud_agent-2.3.4}/nextcloud_agent.egg-info/requires.txt +1 -7
- {nextcloud_agent-2.3.2 → nextcloud_agent-2.3.4}/nextcloud_agent.egg-info/top_level.txt +0 -1
- {nextcloud_agent-2.3.2 → nextcloud_agent-2.3.4}/pyproject.toml +14 -17
- {nextcloud_agent-2.3.2 → nextcloud_agent-2.3.4}/tests/test_fleet_name.py +3 -14
- {nextcloud_agent-2.3.2 → nextcloud_agent-2.3.4}/tests/test_init.py +2 -2
- {nextcloud_agent-2.3.2 → nextcloud_agent-2.3.4}/tests/test_kg_ingest.py +2 -2
- nextcloud_agent-2.3.4/tests/test_mcp_server.py +52 -0
- nextcloud_agent-2.3.2/nextcloud_agent/__init__.py +0 -1
- nextcloud_agent-2.3.2/nextcloud_agent/__main__.py +0 -4
- nextcloud_agent-2.3.2/nextcloud_agent/connectors/__init__.py +0 -0
- nextcloud_agent-2.3.2/nextcloud_agent/connectors/mcp_source_presets.json +0 -14
- nextcloud_agent-2.3.2/nextcloud_agent/connectors/tool_schema_fingerprints.json +0 -8
- nextcloud_agent-2.3.2/nextcloud_agent/prompts/__init__.py +0 -0
- nextcloud_agent-2.3.2/nextcloud_agent/skills/__init__.py +0 -0
- nextcloud_agent-2.3.2/nextcloud_agent.egg-info/entry_points.txt +0 -17
- nextcloud_agent-2.3.2/scripts/security_sanitizer.py +0 -318
- nextcloud_agent-2.3.2/scripts/verify_api_integration.py +0 -320
- nextcloud_agent-2.3.2/tests/test_cli_server.py +0 -18
- nextcloud_agent-2.3.2/tests/test_default_content_surfaces.py +0 -43
- nextcloud_agent-2.3.2/tests/test_mcp_server.py +0 -100
- {nextcloud_agent-2.3.2 → nextcloud_agent-2.3.4}/LICENSE +0 -0
- {nextcloud_agent-2.3.2 → nextcloud_agent-2.3.4}/nextcloud_agent/api/__init__.py +0 -0
- {nextcloud_agent-2.3.2 → nextcloud_agent-2.3.4}/nextcloud_agent/api/api_client_base.py +0 -0
- {nextcloud_agent-2.3.2 → nextcloud_agent-2.3.4}/nextcloud_agent/api/api_client_calendar.py +0 -0
- {nextcloud_agent-2.3.2 → nextcloud_agent-2.3.4}/nextcloud_agent/api/api_client_contacts.py +0 -0
- {nextcloud_agent-2.3.2 → nextcloud_agent-2.3.4}/nextcloud_agent/api/api_client_files.py +0 -0
- {nextcloud_agent-2.3.2 → nextcloud_agent-2.3.4}/nextcloud_agent/api/xml_security.py +0 -0
- {nextcloud_agent-2.3.2 → nextcloud_agent-2.3.4}/nextcloud_agent/api_client.py +0 -0
- {nextcloud_agent-2.3.2 → nextcloud_agent-2.3.4}/nextcloud_agent/auth.py +0 -0
- {nextcloud_agent-2.3.2 → nextcloud_agent-2.3.4}/nextcloud_agent/mcp_config.json +0 -0
- {nextcloud_agent-2.3.2 → nextcloud_agent-2.3.4}/nextcloud_agent/ontology/__init__.py +0 -0
- {nextcloud_agent-2.3.2 → nextcloud_agent-2.3.4}/nextcloud_agent/ontology/fixtures/records.json +0 -0
- {nextcloud_agent-2.3.2 → nextcloud_agent-2.3.4}/nextcloud_agent/ontology/migrations/manifest.json +0 -0
- {nextcloud_agent-2.3.2 → nextcloud_agent-2.3.4}/nextcloud_agent/ontology/shapes/connector.shacl.ttl +0 -0
- {nextcloud_agent-2.3.2 → nextcloud_agent-2.3.4}/nextcloud_agent/skills/nextcloud-agent-operations/SKILL.md +0 -0
- {nextcloud_agent-2.3.2 → nextcloud_agent-2.3.4}/nextcloud_agent/skills/nextcloud-agent-operations/agents/openai.yaml +0 -0
- {nextcloud_agent-2.3.2 → nextcloud_agent-2.3.4}/nextcloud_agent/skills/nextcloud-agent-operations/references/catalog.md +0 -0
- {nextcloud_agent-2.3.2 → nextcloud_agent-2.3.4}/nextcloud_agent/skills/nextcloud-files/SKILL.md +0 -0
- {nextcloud_agent-2.3.2 → nextcloud_agent-2.3.4}/nextcloud_agent/skills/nextcloud-files/WORKFLOW.md +0 -0
- {nextcloud_agent-2.3.2 → nextcloud_agent-2.3.4}/nextcloud_agent/skills/nextcloud-ingest/SKILL.md +0 -0
- {nextcloud_agent-2.3.2 → nextcloud_agent-2.3.4}/nextcloud_agent/skills/nextcloud-ingest/WORKFLOW.md +0 -0
- {nextcloud_agent-2.3.2 → nextcloud_agent-2.3.4}/nextcloud_agent/skills/nextcloud-shares/SKILL.md +0 -0
- {nextcloud_agent-2.3.2 → nextcloud_agent-2.3.4}/nextcloud_agent/skills/nextcloud-shares/WORKFLOW.md +0 -0
- {nextcloud_agent-2.3.2 → nextcloud_agent-2.3.4}/nextcloud_agent.egg-info/dependency_links.txt +0 -0
- {nextcloud_agent-2.3.2 → nextcloud_agent-2.3.4}/setup.cfg +0 -0
- {nextcloud_agent-2.3.2 → nextcloud_agent-2.3.4}/tests/conftest.py +0 -0
- {nextcloud_agent-2.3.2 → nextcloud_agent-2.3.4}/tests/test_api_client.py +0 -0
- {nextcloud_agent-2.3.2 → nextcloud_agent-2.3.4}/tests/test_auth.py +0 -0
- {nextcloud_agent-2.3.2 → nextcloud_agent-2.3.4}/tests/test_init_dynamics.py +0 -0
- {nextcloud_agent-2.3.2 → nextcloud_agent-2.3.4}/tests/test_xml_security.py +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nextcloud-agent
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.4
|
|
4
4
|
Summary: Nextcloud MCP Server for Agentic AI!
|
|
5
|
-
Author-email:
|
|
5
|
+
Author-email: Repository Maintainers <maintainers@knuckles.team>
|
|
6
6
|
License: MIT
|
|
7
7
|
Classifier: Development Status :: 3 - Alpha
|
|
8
8
|
Classifier: License :: OSI Approved :: MIT License
|
|
@@ -12,16 +12,12 @@ Classifier: Programming Language :: Python :: 3
|
|
|
12
12
|
Requires-Python: >=3.12
|
|
13
13
|
Description-Content-Type: text/markdown
|
|
14
14
|
License-File: LICENSE
|
|
15
|
-
Requires-Dist: agent-connector-sdk[mcp]<
|
|
15
|
+
Requires-Dist: agent-connector-sdk[mcp]<0.6.0,>=0.5.4
|
|
16
16
|
Requires-Dist: requests>=2.34.2
|
|
17
17
|
Requires-Dist: defusedxml>=0.7.1
|
|
18
18
|
Requires-Dist: python-dateutil>=2.9.0.post0
|
|
19
19
|
Requires-Dist: icalendar>=7.3.0
|
|
20
20
|
Requires-Dist: vobject>=0.9.9
|
|
21
|
-
Provides-Extra: mcp
|
|
22
|
-
Requires-Dist: agent-connector-sdk[mcp]<1.0.0,>=0.3.18; extra == "mcp"
|
|
23
|
-
Provides-Extra: all
|
|
24
|
-
Requires-Dist: agent-connector-sdk[mcp]<1.0.0,>=0.3.18; extra == "all"
|
|
25
21
|
Provides-Extra: test
|
|
26
22
|
Requires-Dist: pytest-xdist>=3.8.0; extra == "test"
|
|
27
23
|
Requires-Dist: pytest>=9.1.1; extra == "test"
|
|
@@ -51,8 +47,6 @@ Dynamic: license-file
|
|
|
51
47
|

|
|
52
48
|

|
|
53
49
|
|
|
54
|
-
*Version: 2.3.2*
|
|
55
|
-
|
|
56
50
|
> **Documentation** — Installation, deployment, usage across the API, CLI, and MCP
|
|
57
51
|
> interfaces, and guidance for provisioning the backing Nextcloud instance are
|
|
58
52
|
> maintained in the [official documentation](https://knuckles-team.github.io/nextcloud-agent/).
|
|
@@ -353,7 +347,7 @@ services:
|
|
|
353
347
|
max-file: "3"
|
|
354
348
|
|
|
355
349
|
nextcloud-agent-agent:
|
|
356
|
-
image: knucklessg1/nextcloud-agent:2.3.
|
|
350
|
+
image: knucklessg1/nextcloud-agent:2.3.3
|
|
357
351
|
container_name: nextcloud-agent-agent
|
|
358
352
|
hostname: nextcloud-agent-agent
|
|
359
353
|
restart: always
|
|
@@ -524,15 +518,15 @@ One multi-stage `docker/Dockerfile` builds two right-sized images, selected by `
|
|
|
524
518
|
| Image tag | Build target | Contents | Entrypoint |
|
|
525
519
|
|-----------|--------------|----------|------------|
|
|
526
520
|
| `knucklessg1/nextcloud-agent:mcp` | `--target mcp` | `nextcloud-agent[mcp]` — **connector-focused**, includes `epistemic-graph[full]`; no model-orchestration stack | `nextcloud-mcp` |
|
|
527
|
-
| `knucklessg1/nextcloud-agent:2.3.
|
|
521
|
+
| `knucklessg1/nextcloud-agent:2.3.3` | `--target agent` (default) | `nextcloud-agent[agent]` — **agent runtime**, model orchestration + `epistemic-graph[full]` | `nextcloud-agent` |
|
|
528
522
|
|
|
529
523
|
```bash
|
|
530
524
|
docker build --target mcp -t knucklessg1/nextcloud-agent:mcp docker/ # connector-focused MCP server
|
|
531
|
-
docker build --target agent -t knucklessg1/nextcloud-agent:2.3.
|
|
525
|
+
docker build --target agent -t knucklessg1/nextcloud-agent:2.3.3 docker/ # agent runtime
|
|
532
526
|
```
|
|
533
527
|
|
|
534
528
|
`docker/mcp.compose.yml` runs the connector-focused `:mcp` server; `docker/agent.compose.yml` runs the
|
|
535
|
-
agent (`:2.3.
|
|
529
|
+
agent (`:2.3.3`) with a co-located `:mcp` sidecar.
|
|
536
530
|
|
|
537
531
|
### Knowledge-graph database (`epistemic-graph`)
|
|
538
532
|
|
|
@@ -596,7 +590,7 @@ to just this package. Ask your agent to **"deploy `nextcloud-agent` with agent-o
|
|
|
596
590
|
|------|---------|
|
|
597
591
|
| Bare-metal, prod (PyPI) | `uvx nextcloud-mcp` · or `uv tool install nextcloud-agent` |
|
|
598
592
|
| Bare-metal, dev (editable) | `uv pip install -e ".[all]"` · or `pip install -e ".[all]"` |
|
|
599
|
-
| Container, prod | deploy `knucklessg1/nextcloud-agent:2.3.
|
|
593
|
+
| Container, prod | deploy `knucklessg1/nextcloud-agent:2.3.3` via docker-compose / swarm / podman / podman-compose / kubernetes |
|
|
600
594
|
| Container, dev (editable) | deploy `docker/compose.dev.yml` (source-mounted at `/src`; edits live on restart) |
|
|
601
595
|
|
|
602
596
|
Secrets are read-existing + seeded via `vault_sync` — you are only prompted for what's missing.
|
|
@@ -617,7 +611,7 @@ to **"deploy `nextcloud-agent` with agent-connector-sdk-deployment"**.
|
|
|
617
611
|
|------|---------|
|
|
618
612
|
| Installed package | `uv tool install "nextcloud-agent[mcp]"`, then run `nextcloud-mcp` |
|
|
619
613
|
| Editable source | `uv pip install -e ".[agent]"`, then run `nextcloud-mcp` |
|
|
620
|
-
| Immutable container | deploy `knucklessg1/nextcloud-agent:2.3.
|
|
614
|
+
| Immutable container | deploy `knucklessg1/nextcloud-agent:2.3.3` (or a pinned `@sha256:<digest>`) through the operator-selected orchestrator |
|
|
621
615
|
|
|
622
616
|
The repository embeds no deployment profile, credential value, certificate path, or
|
|
623
617
|
environment-specific endpoint. Supply those at runtime through `AgentConfig` and the
|
|
@@ -20,8 +20,6 @@
|
|
|
20
20
|

|
|
21
21
|

|
|
22
22
|
|
|
23
|
-
*Version: 2.3.2*
|
|
24
|
-
|
|
25
23
|
> **Documentation** — Installation, deployment, usage across the API, CLI, and MCP
|
|
26
24
|
> interfaces, and guidance for provisioning the backing Nextcloud instance are
|
|
27
25
|
> maintained in the [official documentation](https://knuckles-team.github.io/nextcloud-agent/).
|
|
@@ -322,7 +320,7 @@ services:
|
|
|
322
320
|
max-file: "3"
|
|
323
321
|
|
|
324
322
|
nextcloud-agent-agent:
|
|
325
|
-
image: knucklessg1/nextcloud-agent:2.3.
|
|
323
|
+
image: knucklessg1/nextcloud-agent:2.3.3
|
|
326
324
|
container_name: nextcloud-agent-agent
|
|
327
325
|
hostname: nextcloud-agent-agent
|
|
328
326
|
restart: always
|
|
@@ -493,15 +491,15 @@ One multi-stage `docker/Dockerfile` builds two right-sized images, selected by `
|
|
|
493
491
|
| Image tag | Build target | Contents | Entrypoint |
|
|
494
492
|
|-----------|--------------|----------|------------|
|
|
495
493
|
| `knucklessg1/nextcloud-agent:mcp` | `--target mcp` | `nextcloud-agent[mcp]` — **connector-focused**, includes `epistemic-graph[full]`; no model-orchestration stack | `nextcloud-mcp` |
|
|
496
|
-
| `knucklessg1/nextcloud-agent:2.3.
|
|
494
|
+
| `knucklessg1/nextcloud-agent:2.3.3` | `--target agent` (default) | `nextcloud-agent[agent]` — **agent runtime**, model orchestration + `epistemic-graph[full]` | `nextcloud-agent` |
|
|
497
495
|
|
|
498
496
|
```bash
|
|
499
497
|
docker build --target mcp -t knucklessg1/nextcloud-agent:mcp docker/ # connector-focused MCP server
|
|
500
|
-
docker build --target agent -t knucklessg1/nextcloud-agent:2.3.
|
|
498
|
+
docker build --target agent -t knucklessg1/nextcloud-agent:2.3.3 docker/ # agent runtime
|
|
501
499
|
```
|
|
502
500
|
|
|
503
501
|
`docker/mcp.compose.yml` runs the connector-focused `:mcp` server; `docker/agent.compose.yml` runs the
|
|
504
|
-
agent (`:2.3.
|
|
502
|
+
agent (`:2.3.3`) with a co-located `:mcp` sidecar.
|
|
505
503
|
|
|
506
504
|
### Knowledge-graph database (`epistemic-graph`)
|
|
507
505
|
|
|
@@ -565,7 +563,7 @@ to just this package. Ask your agent to **"deploy `nextcloud-agent` with agent-o
|
|
|
565
563
|
|------|---------|
|
|
566
564
|
| Bare-metal, prod (PyPI) | `uvx nextcloud-mcp` · or `uv tool install nextcloud-agent` |
|
|
567
565
|
| Bare-metal, dev (editable) | `uv pip install -e ".[all]"` · or `pip install -e ".[all]"` |
|
|
568
|
-
| Container, prod | deploy `knucklessg1/nextcloud-agent:2.3.
|
|
566
|
+
| Container, prod | deploy `knucklessg1/nextcloud-agent:2.3.3` via docker-compose / swarm / podman / podman-compose / kubernetes |
|
|
569
567
|
| Container, dev (editable) | deploy `docker/compose.dev.yml` (source-mounted at `/src`; edits live on restart) |
|
|
570
568
|
|
|
571
569
|
Secrets are read-existing + seeded via `vault_sync` — you are only prompted for what's missing.
|
|
@@ -586,7 +584,7 @@ to **"deploy `nextcloud-agent` with agent-connector-sdk-deployment"**.
|
|
|
586
584
|
|------|---------|
|
|
587
585
|
| Installed package | `uv tool install "nextcloud-agent[mcp]"`, then run `nextcloud-mcp` |
|
|
588
586
|
| Editable source | `uv pip install -e ".[agent]"`, then run `nextcloud-mcp` |
|
|
589
|
-
| Immutable container | deploy `knucklessg1/nextcloud-agent:2.3.
|
|
587
|
+
| Immutable container | deploy `knucklessg1/nextcloud-agent:2.3.3` (or a pinned `@sha256:<digest>`) through the operator-selected orchestrator |
|
|
590
588
|
|
|
591
589
|
The repository embeds no deployment profile, credential value, certificate path, or
|
|
592
590
|
environment-specific endpoint. Supply those at runtime through `AgentConfig` and the
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from agent_connector_sdk.connector import Connector
|
|
2
|
+
|
|
3
|
+
from nextcloud_agent.api_client import NextcloudAPI
|
|
4
|
+
from nextcloud_agent.auth import get_client
|
|
5
|
+
|
|
6
|
+
connector = Connector(
|
|
7
|
+
api=NextcloudAPI,
|
|
8
|
+
get_client=get_client,
|
|
9
|
+
tools="nextcloud_agent.mcp_server",
|
|
10
|
+
instructions="nextcloud-agent MCP Server — Condensed Action-Routed Tools.",
|
|
11
|
+
)
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"""Data sources of this connector, declared by tool name (generated by connector-ontology-map migrate).
|
|
2
|
+
|
|
3
|
+
Served live as ``connector://resources``. Regenerate by editing the declarations, not the tools.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
# ruff: noqa: E501
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
from agent_connector_sdk.ingest.live_declaration import source_meta
|
|
12
|
+
|
|
13
|
+
SOURCES: tuple[Any, ...] = (
|
|
14
|
+
source_meta(
|
|
15
|
+
tool="nextcloud_list_files",
|
|
16
|
+
source_id="nextcloud-files",
|
|
17
|
+
record_type="File",
|
|
18
|
+
id_field="file_id",
|
|
19
|
+
cursor_field="last_modified",
|
|
20
|
+
preset={
|
|
21
|
+
"doc_type": "file",
|
|
22
|
+
"params_style": "args",
|
|
23
|
+
},
|
|
24
|
+
records_path="",
|
|
25
|
+
server="nextcloud-mcp",
|
|
26
|
+
text_field="name",
|
|
27
|
+
title_field="name",
|
|
28
|
+
),
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
SCHEMA_VERSION = 2
|
|
32
|
+
|
|
33
|
+
FIELD_SETS: dict[str, dict[str, str]] = {
|
|
34
|
+
"fields_1": {
|
|
35
|
+
"mimeType": "xsd:string",
|
|
36
|
+
"modifiedAt": "xsd:string",
|
|
37
|
+
"path": "xsd:string",
|
|
38
|
+
"sizeBytes": "xsd:integer",
|
|
39
|
+
},
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
SCHEMA_MAPPINGS: dict[str, Any] = {
|
|
43
|
+
"CalendarEvent": {
|
|
44
|
+
"field_sets": ["fields_1"],
|
|
45
|
+
"ontology_class": "Event",
|
|
46
|
+
},
|
|
47
|
+
"File": {
|
|
48
|
+
"field_sets": ["fields_1"],
|
|
49
|
+
"ontology_class": "File",
|
|
50
|
+
},
|
|
51
|
+
"Folder": {
|
|
52
|
+
"field_sets": ["fields_1"],
|
|
53
|
+
"ontology_class": None,
|
|
54
|
+
},
|
|
55
|
+
"Share": {
|
|
56
|
+
"field_sets": ["fields_1"],
|
|
57
|
+
"ontology_class": None,
|
|
58
|
+
},
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
RESOURCES: tuple[dict[str, str], ...] = (
|
|
62
|
+
{
|
|
63
|
+
"id_prefix": "calendarevent",
|
|
64
|
+
"label": "Calendar Event",
|
|
65
|
+
"name": "CalendarEvent",
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"id_prefix": "file",
|
|
69
|
+
"label": "Nextcloud File",
|
|
70
|
+
"name": "File",
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"id_prefix": "folder",
|
|
74
|
+
"label": "Nextcloud Folder",
|
|
75
|
+
"name": "Folder",
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"id_prefix": "share",
|
|
79
|
+
"label": "Nextcloud Share",
|
|
80
|
+
"name": "Share",
|
|
81
|
+
},
|
|
82
|
+
)
|
|
@@ -17,65 +17,11 @@ import posixpath
|
|
|
17
17
|
from typing import Any
|
|
18
18
|
|
|
19
19
|
from agent_connector_sdk.ingest import (
|
|
20
|
-
ChangeSet,
|
|
21
|
-
Entity,
|
|
22
|
-
IngestBinding,
|
|
23
|
-
IngestError,
|
|
24
20
|
KnowledgeIngest,
|
|
25
|
-
|
|
26
|
-
current_ingest,
|
|
21
|
+
SourceStream,
|
|
27
22
|
)
|
|
28
23
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
_ENTITY_RESERVED_KEYS = frozenset({"id", "node_type"})
|
|
32
|
-
_RELATIONSHIP_RESERVED_KEYS = frozenset({"source", "target", "relationship"})
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
def _to_entity(record: dict[str, Any]) -> Entity:
|
|
36
|
-
return Entity(
|
|
37
|
-
id=record.get("id"),
|
|
38
|
-
node_type=record.get("node_type"),
|
|
39
|
-
properties={
|
|
40
|
-
key: value
|
|
41
|
-
for key, value in record.items()
|
|
42
|
-
if key not in _ENTITY_RESERVED_KEYS
|
|
43
|
-
},
|
|
44
|
-
)
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
def _to_relationship(record: dict[str, Any]) -> Relationship:
|
|
48
|
-
properties = {
|
|
49
|
-
key: value
|
|
50
|
-
for key, value in record.items()
|
|
51
|
-
if key not in _RELATIONSHIP_RESERVED_KEYS
|
|
52
|
-
}
|
|
53
|
-
return Relationship(
|
|
54
|
-
source=record["source"],
|
|
55
|
-
target=record["target"],
|
|
56
|
-
relationship=record["relationship"],
|
|
57
|
-
properties=properties or None,
|
|
58
|
-
)
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
async def _ingest(
|
|
62
|
-
entities: list[dict[str, Any]],
|
|
63
|
-
relationships: list[dict[str, Any]] | None = None,
|
|
64
|
-
*,
|
|
65
|
-
ingest: KnowledgeIngest | None = None,
|
|
66
|
-
) -> dict[str, int]:
|
|
67
|
-
"""Route typed nodes/edges through the SDK ingest facade (injectable for tests)."""
|
|
68
|
-
if not entities:
|
|
69
|
-
raise IngestError("ingest needs at least one entity")
|
|
70
|
-
change_set = ChangeSet(
|
|
71
|
-
entities=tuple(_to_entity(entity) for entity in entities),
|
|
72
|
-
relationships=tuple(
|
|
73
|
-
_to_relationship(relationship) for relationship in relationships or ()
|
|
74
|
-
),
|
|
75
|
-
)
|
|
76
|
-
service = ingest or current_ingest()
|
|
77
|
-
receipt = await service.submit(_BINDING, change_set)
|
|
78
|
-
return {"nodes": receipt.affected_count, "edges": receipt.relationship_count}
|
|
24
|
+
STREAM = SourceStream.for_package(__package__.split(".")[0], "nextcloud")
|
|
79
25
|
|
|
80
26
|
|
|
81
27
|
async def ingest_listing(
|
|
@@ -143,7 +89,7 @@ async def ingest_listing(
|
|
|
143
89
|
{"source": node["id"], "target": parent_id, "relationship": "inFolder"}
|
|
144
90
|
)
|
|
145
91
|
|
|
146
|
-
return await
|
|
92
|
+
return await STREAM.entities(entities, relationships, ingest=ingest)
|
|
147
93
|
|
|
148
94
|
|
|
149
95
|
async def ingest_shares(
|
|
@@ -192,7 +138,7 @@ async def ingest_shares(
|
|
|
192
138
|
)
|
|
193
139
|
if not entities:
|
|
194
140
|
return None
|
|
195
|
-
return await
|
|
141
|
+
return await STREAM.entities(entities, relationships, ingest=ingest)
|
|
196
142
|
|
|
197
143
|
|
|
198
144
|
async def ingest_calendar_events(
|
|
@@ -218,4 +164,4 @@ async def ingest_calendar_events(
|
|
|
218
164
|
)
|
|
219
165
|
if not entities:
|
|
220
166
|
return None
|
|
221
|
-
return await
|
|
167
|
+
return await STREAM.entities(entities, None, ingest=ingest)
|
|
@@ -3,7 +3,6 @@ import warnings
|
|
|
3
3
|
|
|
4
4
|
from fastmcp import Context, FastMCP
|
|
5
5
|
from fastmcp.dependencies import Depends
|
|
6
|
-
from fastmcp.utilities.logging import get_logger
|
|
7
6
|
from pydantic import Field
|
|
8
7
|
|
|
9
8
|
# Filter RequestsDependencyWarning early to prevent log spam
|
|
@@ -19,26 +18,12 @@ with warnings.catch_warnings():
|
|
|
19
18
|
warnings.filterwarnings("ignore", message=".*urllib3.*or chardet.*")
|
|
20
19
|
warnings.filterwarnings("ignore", message=".*urllib3.*or charset_normalizer.*")
|
|
21
20
|
|
|
22
|
-
import logging
|
|
23
|
-
import sys
|
|
24
|
-
from typing import Any
|
|
25
21
|
|
|
26
|
-
from agent_connector_sdk.config import load_config
|
|
27
22
|
from agent_connector_sdk.mcp.action_dispatch import resolve_action
|
|
28
23
|
from agent_connector_sdk.mcp.concurrency import run_blocking
|
|
29
|
-
from agent_connector_sdk.mcp.server import create_mcp_server
|
|
30
|
-
from agent_connector_sdk.mcp.tool_surface import register_tool_surface
|
|
31
|
-
from starlette.requests import Request
|
|
32
|
-
from starlette.responses import JSONResponse
|
|
33
24
|
|
|
34
|
-
from nextcloud_agent.api_client import NextcloudAPI
|
|
35
25
|
from nextcloud_agent.auth import get_client
|
|
36
26
|
|
|
37
|
-
__version__ = "2.3.2"
|
|
38
|
-
|
|
39
|
-
logger = get_logger(name="nextcloud-agent")
|
|
40
|
-
logger.setLevel(logging.INFO)
|
|
41
|
-
|
|
42
27
|
|
|
43
28
|
def register_files_tools(mcp: FastMCP):
|
|
44
29
|
"""
|
|
@@ -303,56 +288,3 @@ def register_contacts_tools(mcp: FastMCP):
|
|
|
303
288
|
if action == "create_contact":
|
|
304
289
|
return await run_blocking(client.create_contact, **kwargs)
|
|
305
290
|
raise ValueError(f"Unknown action: {action}")
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
def get_mcp_instance() -> tuple[Any, ...]:
|
|
309
|
-
"""
|
|
310
|
-
Initialize and return the MCP instance.
|
|
311
|
-
"""
|
|
312
|
-
load_config()
|
|
313
|
-
args, mcp, middlewares = create_mcp_server(
|
|
314
|
-
name="nextcloud-agent MCP",
|
|
315
|
-
version=__version__,
|
|
316
|
-
instructions="nextcloud-agent MCP Server — Condensed Action-Routed Tools.",
|
|
317
|
-
)
|
|
318
|
-
|
|
319
|
-
@mcp.custom_route("/health", methods=["GET"])
|
|
320
|
-
async def health_check(request: Request) -> JSONResponse:
|
|
321
|
-
return JSONResponse({"status": "OK"})
|
|
322
|
-
|
|
323
|
-
register_tool_surface(
|
|
324
|
-
mcp,
|
|
325
|
-
client_cls=NextcloudAPI,
|
|
326
|
-
get_client=get_client,
|
|
327
|
-
service="nextcloud-agent",
|
|
328
|
-
tools_module=sys.modules[__name__],
|
|
329
|
-
)
|
|
330
|
-
|
|
331
|
-
for mw in middlewares:
|
|
332
|
-
mcp.add_middleware(mw)
|
|
333
|
-
return mcp, args, middlewares
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
def mcp_server() -> None:
|
|
337
|
-
"""
|
|
338
|
-
Launch the MCP server process.
|
|
339
|
-
"""
|
|
340
|
-
mcp, args, middlewares = get_mcp_instance()
|
|
341
|
-
print(f"nextcloud-agent MCP v{__version__}", file=sys.stderr)
|
|
342
|
-
print("\nStarting MCP Server", file=sys.stderr)
|
|
343
|
-
print(f" Transport: {args.transport.upper()}", file=sys.stderr)
|
|
344
|
-
print(f" Auth: {args.auth_type}", file=sys.stderr)
|
|
345
|
-
|
|
346
|
-
if args.transport == "stdio":
|
|
347
|
-
mcp.run(transport="stdio")
|
|
348
|
-
elif args.transport == "streamable-http":
|
|
349
|
-
mcp.run(transport="streamable-http", host=args.host, port=args.port)
|
|
350
|
-
elif args.transport == "sse":
|
|
351
|
-
mcp.run(transport="sse", host=args.host, port=args.port)
|
|
352
|
-
else:
|
|
353
|
-
logger.error("Invalid transport", extra={"transport": args.transport})
|
|
354
|
-
sys.exit(1)
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
if __name__ == "__main__":
|
|
358
|
-
mcp_server()
|
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
{
|
|
2
|
-
"api_version": "
|
|
2
|
+
"api_version": "graphos.io/v1",
|
|
3
3
|
"artifacts": {
|
|
4
|
-
"connector_manifest.yml": "3ce0f7ad3717ff79b1a269b91f29f09159309cdadc3663daa22e982b18b85a41",
|
|
5
|
-
"nextcloud_agent/connectors/mcp_source_presets.json": "c414c7c710127203405dd518135916111e0b2f197f4e4edcc25588c0d281f8ce",
|
|
6
|
-
"nextcloud_agent/connectors/tool_schema_fingerprints.json": "f1b99eb4cb9c36df8c61b3beb915c95c45204cbca82de59098c0bcc2f9c814ec",
|
|
7
4
|
"nextcloud_agent/ontology/fixtures/records.json": "aeff7048eae4bc5068dcd2070ad0f0e02b1de63bf9fd5dbecf6a51c5ebd26dc7",
|
|
8
|
-
"nextcloud_agent/ontology/mappings/source.yaml": "
|
|
5
|
+
"nextcloud_agent/ontology/mappings/source.yaml": "88a1d3c331f53626adcb3998eb8f262a33a59065ad8f99ad70e7a82a14c41d49",
|
|
9
6
|
"nextcloud_agent/ontology/migrations/manifest.json": "25716b991f14c59cc202177dfa6d410b396e18a5c9accc92238e5433825535e7",
|
|
10
|
-
"nextcloud_agent/ontology/nextcloud.ttl": "
|
|
7
|
+
"nextcloud_agent/ontology/nextcloud.ttl": "19a6a86795f930ab216e58fa59f02aa4f26ccf0cd08a3dee859383b640d1f30f",
|
|
11
8
|
"nextcloud_agent/ontology/shapes/connector.shacl.ttl": "9a8192289bd6b9a24b4d215cf0fe0391d7e706cf461704dff4c537b5f82724f6"
|
|
12
9
|
},
|
|
13
10
|
"checks": {
|
|
@@ -18,11 +15,11 @@
|
|
|
18
15
|
"synthetic_fixture_contract": "passed"
|
|
19
16
|
},
|
|
20
17
|
"compatibility": {
|
|
21
|
-
"
|
|
18
|
+
"agent_utilities": ">=2.5.0,<3",
|
|
22
19
|
"bundle_schema": "2",
|
|
23
20
|
"epistemic_graph": ">=2.27.0,<3"
|
|
24
21
|
},
|
|
25
|
-
"connector": "nextcloud-
|
|
22
|
+
"connector": "nextcloud-agent",
|
|
26
23
|
"kind": "ConnectorSourceAttestation",
|
|
27
24
|
"live_certified": false,
|
|
28
25
|
"mode": "offline-source",
|
|
@@ -32,5 +29,5 @@
|
|
|
32
29
|
"signer": "UNSIGNED-PREVIEW",
|
|
33
30
|
"signing_public_key": "",
|
|
34
31
|
"status": "source-validated",
|
|
35
|
-
"validated_at": "2026-
|
|
32
|
+
"validated_at": "2026-10-24T13:49:17Z"
|
|
36
33
|
}
|
|
@@ -14,21 +14,18 @@
|
|
|
14
14
|
# :AssetOccurrence / :Blob / :Document are defined by the hub base ontology and are only
|
|
15
15
|
# REFERENCED here (never redefined).
|
|
16
16
|
|
|
17
|
-
:File a owl:Class
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
:File a owl:Class .
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
:Folder a owl:Class .
|
|
20
21
|
|
|
21
|
-
:Folder a owl:Class ;
|
|
22
|
-
rdfs:label "Nextcloud Folder" ;
|
|
23
|
-
rdfs:comment "A WebDAV collection (directory) that contains files and subfolders (nextcloud_files list_files)." .
|
|
24
22
|
|
|
25
23
|
:Share a owl:Class ;
|
|
26
24
|
rdfs:label "Nextcloud Share" ;
|
|
27
25
|
rdfs:comment "A sharing grant on a file or folder — public link, user, or group (nextcloud_sharing list_shares)." .
|
|
28
26
|
|
|
29
|
-
:CalendarEvent a owl:Class
|
|
30
|
-
|
|
31
|
-
rdfs:comment "A CalDAV calendar event (.ics) hosted in Nextcloud (nextcloud_calendar list_calendar_events)." .
|
|
27
|
+
:CalendarEvent a owl:Class .
|
|
28
|
+
|
|
32
29
|
|
|
33
30
|
# --- links (owl:ObjectProperty) ---
|
|
34
31
|
|
|
@@ -88,5 +85,7 @@
|
|
|
88
85
|
rdfs:comment """Nextcloud file-storage and collaboration model — files, folders, shares
|
|
89
86
|
and calendar events over WebDAV/CalDAV — federated into the agent-connector-sdk
|
|
90
87
|
knowledge-graph hub. Files carry their raw bytes as federated :AssetOccurrence/:Blob
|
|
91
|
-
(via :hasBlob) and their extracted text as federated :Document nodes."""
|
|
92
|
-
|
|
88
|
+
(via :hasBlob) and their extracted text as federated :Document nodes.""" .
|
|
89
|
+
|
|
90
|
+
# ontology-codemod R4
|
|
91
|
+
<http://knuckles.team/kg#Share> rdfs:subClassOf <http://knuckles.team/kg#Resource> .
|
|
@@ -4,8 +4,6 @@
|
|
|
4
4
|
"schema_version": "1.0",
|
|
5
5
|
"prompt_version": "0.1.0",
|
|
6
6
|
"source": "nextcloud-agent",
|
|
7
|
-
"extends": "agent-connector-sdk:base",
|
|
8
|
-
"compose": "append",
|
|
9
7
|
"description": "Nextcloud file steward: browse, share, and natively ingest files and folders into the knowledge graph over the nextcloud-agent MCP server.",
|
|
10
8
|
"metadata": {
|
|
11
9
|
"topic": "Nextcloud file stewardship",
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nextcloud-agent
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.4
|
|
4
4
|
Summary: Nextcloud MCP Server for Agentic AI!
|
|
5
|
-
Author-email:
|
|
5
|
+
Author-email: Repository Maintainers <maintainers@knuckles.team>
|
|
6
6
|
License: MIT
|
|
7
7
|
Classifier: Development Status :: 3 - Alpha
|
|
8
8
|
Classifier: License :: OSI Approved :: MIT License
|
|
@@ -12,16 +12,12 @@ Classifier: Programming Language :: Python :: 3
|
|
|
12
12
|
Requires-Python: >=3.12
|
|
13
13
|
Description-Content-Type: text/markdown
|
|
14
14
|
License-File: LICENSE
|
|
15
|
-
Requires-Dist: agent-connector-sdk[mcp]<
|
|
15
|
+
Requires-Dist: agent-connector-sdk[mcp]<0.6.0,>=0.5.4
|
|
16
16
|
Requires-Dist: requests>=2.34.2
|
|
17
17
|
Requires-Dist: defusedxml>=0.7.1
|
|
18
18
|
Requires-Dist: python-dateutil>=2.9.0.post0
|
|
19
19
|
Requires-Dist: icalendar>=7.3.0
|
|
20
20
|
Requires-Dist: vobject>=0.9.9
|
|
21
|
-
Provides-Extra: mcp
|
|
22
|
-
Requires-Dist: agent-connector-sdk[mcp]<1.0.0,>=0.3.18; extra == "mcp"
|
|
23
|
-
Provides-Extra: all
|
|
24
|
-
Requires-Dist: agent-connector-sdk[mcp]<1.0.0,>=0.3.18; extra == "all"
|
|
25
21
|
Provides-Extra: test
|
|
26
22
|
Requires-Dist: pytest-xdist>=3.8.0; extra == "test"
|
|
27
23
|
Requires-Dist: pytest>=9.1.1; extra == "test"
|
|
@@ -51,8 +47,6 @@ Dynamic: license-file
|
|
|
51
47
|

|
|
52
48
|

|
|
53
49
|
|
|
54
|
-
*Version: 2.3.2*
|
|
55
|
-
|
|
56
50
|
> **Documentation** — Installation, deployment, usage across the API, CLI, and MCP
|
|
57
51
|
> interfaces, and guidance for provisioning the backing Nextcloud instance are
|
|
58
52
|
> maintained in the [official documentation](https://knuckles-team.github.io/nextcloud-agent/).
|
|
@@ -353,7 +347,7 @@ services:
|
|
|
353
347
|
max-file: "3"
|
|
354
348
|
|
|
355
349
|
nextcloud-agent-agent:
|
|
356
|
-
image: knucklessg1/nextcloud-agent:2.3.
|
|
350
|
+
image: knucklessg1/nextcloud-agent:2.3.3
|
|
357
351
|
container_name: nextcloud-agent-agent
|
|
358
352
|
hostname: nextcloud-agent-agent
|
|
359
353
|
restart: always
|
|
@@ -524,15 +518,15 @@ One multi-stage `docker/Dockerfile` builds two right-sized images, selected by `
|
|
|
524
518
|
| Image tag | Build target | Contents | Entrypoint |
|
|
525
519
|
|-----------|--------------|----------|------------|
|
|
526
520
|
| `knucklessg1/nextcloud-agent:mcp` | `--target mcp` | `nextcloud-agent[mcp]` — **connector-focused**, includes `epistemic-graph[full]`; no model-orchestration stack | `nextcloud-mcp` |
|
|
527
|
-
| `knucklessg1/nextcloud-agent:2.3.
|
|
521
|
+
| `knucklessg1/nextcloud-agent:2.3.3` | `--target agent` (default) | `nextcloud-agent[agent]` — **agent runtime**, model orchestration + `epistemic-graph[full]` | `nextcloud-agent` |
|
|
528
522
|
|
|
529
523
|
```bash
|
|
530
524
|
docker build --target mcp -t knucklessg1/nextcloud-agent:mcp docker/ # connector-focused MCP server
|
|
531
|
-
docker build --target agent -t knucklessg1/nextcloud-agent:2.3.
|
|
525
|
+
docker build --target agent -t knucklessg1/nextcloud-agent:2.3.3 docker/ # agent runtime
|
|
532
526
|
```
|
|
533
527
|
|
|
534
528
|
`docker/mcp.compose.yml` runs the connector-focused `:mcp` server; `docker/agent.compose.yml` runs the
|
|
535
|
-
agent (`:2.3.
|
|
529
|
+
agent (`:2.3.3`) with a co-located `:mcp` sidecar.
|
|
536
530
|
|
|
537
531
|
### Knowledge-graph database (`epistemic-graph`)
|
|
538
532
|
|
|
@@ -596,7 +590,7 @@ to just this package. Ask your agent to **"deploy `nextcloud-agent` with agent-o
|
|
|
596
590
|
|------|---------|
|
|
597
591
|
| Bare-metal, prod (PyPI) | `uvx nextcloud-mcp` · or `uv tool install nextcloud-agent` |
|
|
598
592
|
| Bare-metal, dev (editable) | `uv pip install -e ".[all]"` · or `pip install -e ".[all]"` |
|
|
599
|
-
| Container, prod | deploy `knucklessg1/nextcloud-agent:2.3.
|
|
593
|
+
| Container, prod | deploy `knucklessg1/nextcloud-agent:2.3.3` via docker-compose / swarm / podman / podman-compose / kubernetes |
|
|
600
594
|
| Container, dev (editable) | deploy `docker/compose.dev.yml` (source-mounted at `/src`; edits live on restart) |
|
|
601
595
|
|
|
602
596
|
Secrets are read-existing + seeded via `vault_sync` — you are only prompted for what's missing.
|
|
@@ -617,7 +611,7 @@ to **"deploy `nextcloud-agent` with agent-connector-sdk-deployment"**.
|
|
|
617
611
|
|------|---------|
|
|
618
612
|
| Installed package | `uv tool install "nextcloud-agent[mcp]"`, then run `nextcloud-mcp` |
|
|
619
613
|
| Editable source | `uv pip install -e ".[agent]"`, then run `nextcloud-mcp` |
|
|
620
|
-
| Immutable container | deploy `knucklessg1/nextcloud-agent:2.3.
|
|
614
|
+
| Immutable container | deploy `knucklessg1/nextcloud-agent:2.3.3` (or a pinned `@sha256:<digest>`) through the operator-selected orchestrator |
|
|
621
615
|
|
|
622
616
|
The repository embeds no deployment profile, credential value, certificate path, or
|
|
623
617
|
environment-specific endpoint. Supply those at runtime through `AgentConfig` and the
|
|
@@ -5,6 +5,7 @@ nextcloud_agent/__init__.py
|
|
|
5
5
|
nextcloud_agent/__main__.py
|
|
6
6
|
nextcloud_agent/api_client.py
|
|
7
7
|
nextcloud_agent/auth.py
|
|
8
|
+
nextcloud_agent/connector_sources.py
|
|
8
9
|
nextcloud_agent/kg_ingest.py
|
|
9
10
|
nextcloud_agent/mcp_config.json
|
|
10
11
|
nextcloud_agent/mcp_server.py
|
|
@@ -20,9 +21,6 @@ nextcloud_agent/api/api_client_calendar.py
|
|
|
20
21
|
nextcloud_agent/api/api_client_contacts.py
|
|
21
22
|
nextcloud_agent/api/api_client_files.py
|
|
22
23
|
nextcloud_agent/api/xml_security.py
|
|
23
|
-
nextcloud_agent/connectors/__init__.py
|
|
24
|
-
nextcloud_agent/connectors/mcp_source_presets.json
|
|
25
|
-
nextcloud_agent/connectors/tool_schema_fingerprints.json
|
|
26
24
|
nextcloud_agent/ontology/__init__.py
|
|
27
25
|
nextcloud_agent/ontology/certification.json
|
|
28
26
|
nextcloud_agent/ontology/nextcloud.ttl
|
|
@@ -30,9 +28,7 @@ nextcloud_agent/ontology/fixtures/records.json
|
|
|
30
28
|
nextcloud_agent/ontology/mappings/source.yaml
|
|
31
29
|
nextcloud_agent/ontology/migrations/manifest.json
|
|
32
30
|
nextcloud_agent/ontology/shapes/connector.shacl.ttl
|
|
33
|
-
nextcloud_agent/prompts/__init__.py
|
|
34
31
|
nextcloud_agent/prompts/file_steward.json
|
|
35
|
-
nextcloud_agent/skills/__init__.py
|
|
36
32
|
nextcloud_agent/skills/nextcloud-agent-operations/SKILL.md
|
|
37
33
|
nextcloud_agent/skills/nextcloud-agent-operations/agents/openai.yaml
|
|
38
34
|
nextcloud_agent/skills/nextcloud-agent-operations/references/catalog.md
|
|
@@ -42,13 +38,9 @@ nextcloud_agent/skills/nextcloud-ingest/SKILL.md
|
|
|
42
38
|
nextcloud_agent/skills/nextcloud-ingest/WORKFLOW.md
|
|
43
39
|
nextcloud_agent/skills/nextcloud-shares/SKILL.md
|
|
44
40
|
nextcloud_agent/skills/nextcloud-shares/WORKFLOW.md
|
|
45
|
-
scripts/security_sanitizer.py
|
|
46
|
-
scripts/verify_api_integration.py
|
|
47
41
|
tests/conftest.py
|
|
48
42
|
tests/test_api_client.py
|
|
49
43
|
tests/test_auth.py
|
|
50
|
-
tests/test_cli_server.py
|
|
51
|
-
tests/test_default_content_surfaces.py
|
|
52
44
|
tests/test_fleet_name.py
|
|
53
45
|
tests/test_init.py
|
|
54
46
|
tests/test_init_dynamics.py
|