donna 0.2.0__py3-none-any.whl → 0.2.1__py3-none-any.whl
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.
- donna/artifacts/intro.md +39 -0
- donna/artifacts/research/specs/report.md +163 -0
- donna/artifacts/research/work/research.md +198 -0
- donna/artifacts/rfc/specs/request_for_change.md +271 -0
- donna/artifacts/rfc/work/create.md +120 -0
- donna/artifacts/rfc/work/do.md +109 -0
- donna/artifacts/rfc/work/plan.md +68 -0
- donna/artifacts/usage/artifacts.md +41 -6
- donna/artifacts/usage/cli.md +106 -37
- donna/artifacts/usage/worlds.md +8 -2
- donna/cli/__main__.py +1 -1
- donna/cli/commands/artifacts.py +104 -17
- donna/cli/commands/sessions.py +7 -7
- donna/cli/commands/workspaces.py +42 -0
- donna/cli/errors.py +18 -0
- donna/cli/types.py +16 -9
- donna/cli/utils.py +2 -2
- donna/core/errors.py +1 -11
- donna/core/result.py +5 -8
- donna/core/utils.py +0 -3
- donna/lib/__init__.py +4 -0
- donna/lib/sources.py +1 -1
- donna/lib/worlds.py +2 -2
- donna/machine/action_requests.py +0 -5
- donna/machine/artifacts.py +8 -6
- donna/machine/primitives.py +4 -4
- donna/machine/sessions.py +12 -4
- donna/machine/state.py +2 -2
- donna/machine/tasks.py +4 -18
- donna/machine/templates.py +4 -2
- donna/primitives/artifacts/specification.py +13 -2
- donna/primitives/artifacts/workflow.py +11 -2
- donna/primitives/directives/list.py +86 -0
- donna/primitives/directives/view.py +52 -11
- donna/primitives/operations/finish_workflow.py +13 -2
- donna/primitives/operations/output.py +87 -0
- donna/primitives/operations/request_action.py +3 -9
- donna/primitives/operations/run_script.py +2 -2
- donna/protocol/utils.py +22 -0
- donna/workspaces/artifacts.py +238 -0
- donna/{world → workspaces}/artifacts_discovery.py +1 -1
- donna/{world → workspaces}/config.py +13 -6
- donna/{world → workspaces}/errors.py +55 -45
- donna/workspaces/initialization.py +78 -0
- donna/{world → workspaces}/markdown.py +21 -26
- donna/{world → workspaces}/sources/base.py +2 -2
- donna/{world → workspaces}/sources/markdown.py +7 -6
- donna/{world → workspaces}/templates.py +4 -4
- donna/{world → workspaces}/tmp.py +19 -1
- donna/{world → workspaces}/worlds/base.py +5 -2
- donna/{world → workspaces}/worlds/filesystem.py +23 -9
- donna/{world → workspaces}/worlds/python.py +12 -9
- {donna-0.2.0.dist-info → donna-0.2.1.dist-info}/METADATA +4 -1
- donna-0.2.1.dist-info/RECORD +92 -0
- {donna-0.2.0.dist-info → donna-0.2.1.dist-info}/WHEEL +1 -1
- donna/artifacts/work/do_it.md +0 -142
- donna/artifacts/work/do_it_fast.md +0 -98
- donna/artifacts/work/planning.md +0 -245
- donna/cli/commands/projects.py +0 -49
- donna/world/artifacts.py +0 -122
- donna/world/initialization.py +0 -42
- donna/world/worlds/__init__.py +0 -0
- donna-0.2.0.dist-info/RECORD +0 -85
- /donna/{artifacts/work → workspaces}/__init__.py +0 -0
- /donna/{world → workspaces}/sources/__init__.py +0 -0
- /donna/{world → workspaces/worlds}/__init__.py +0 -0
- {donna-0.2.0.dist-info → donna-0.2.1.dist-info}/entry_points.txt +0 -0
- {donna-0.2.0.dist-info → donna-0.2.1.dist-info}/licenses/LICENSE +0 -0
donna/cli/commands/artifacts.py
CHANGED
|
@@ -1,18 +1,42 @@
|
|
|
1
|
+
import builtins
|
|
1
2
|
from collections.abc import Iterable
|
|
2
3
|
|
|
3
4
|
import typer
|
|
4
5
|
|
|
6
|
+
from donna.cli import errors as cli_errors
|
|
5
7
|
from donna.cli.application import app
|
|
6
|
-
from donna.cli.types import
|
|
8
|
+
from donna.cli.types import (
|
|
9
|
+
FullArtifactIdArgument,
|
|
10
|
+
FullArtifactIdPatternArgument,
|
|
11
|
+
InputPathArgument,
|
|
12
|
+
OutputPathOption,
|
|
13
|
+
TagOption,
|
|
14
|
+
)
|
|
7
15
|
from donna.cli.utils import cells_cli, try_initialize_donna
|
|
16
|
+
from donna.core.errors import ErrorsList
|
|
17
|
+
from donna.core.result import Err, Ok, Result
|
|
8
18
|
from donna.domain.ids import FullArtifactIdPattern
|
|
9
19
|
from donna.protocol.cell_shortcuts import operation_succeeded
|
|
10
20
|
from donna.protocol.cells import Cell
|
|
11
|
-
from donna.
|
|
12
|
-
from donna.
|
|
21
|
+
from donna.workspaces import artifacts as world_artifacts
|
|
22
|
+
from donna.workspaces import tmp as world_tmp
|
|
13
23
|
|
|
14
24
|
artifacts_cli = typer.Typer()
|
|
15
25
|
|
|
26
|
+
DEFAULT_ARTIFACT_PATTERN = FullArtifactIdPattern.parse("**").unwrap()
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _parse_slug_with_extension(value: str) -> Result[tuple[str, str], ErrorsList]:
|
|
30
|
+
normalized = value.strip()
|
|
31
|
+
if "." not in normalized:
|
|
32
|
+
return Err([cli_errors.InvalidSlugWithExtension(value=normalized)])
|
|
33
|
+
|
|
34
|
+
slug, extension = normalized.rsplit(".", 1)
|
|
35
|
+
if not slug or not extension:
|
|
36
|
+
return Err([cli_errors.InvalidSlugWithExtension(value=normalized)])
|
|
37
|
+
|
|
38
|
+
return Ok((slug, extension))
|
|
39
|
+
|
|
16
40
|
|
|
17
41
|
@artifacts_cli.callback(invoke_without_command=True)
|
|
18
42
|
def initialize(ctx: typer.Context) -> None:
|
|
@@ -28,20 +52,23 @@ def initialize(ctx: typer.Context) -> None:
|
|
|
28
52
|
help="List artifacts matching a pattern and show their status summaries. Lists all all artifacts by default."
|
|
29
53
|
)
|
|
30
54
|
@cells_cli
|
|
31
|
-
def list(
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
artifacts = world_artifacts.list_artifacts(pattern).unwrap()
|
|
55
|
+
def list(
|
|
56
|
+
pattern: FullArtifactIdPatternArgument = DEFAULT_ARTIFACT_PATTERN,
|
|
57
|
+
tags: TagOption = None,
|
|
58
|
+
) -> Iterable[Cell]:
|
|
59
|
+
artifacts = world_artifacts.list_artifacts(pattern, tags=tags).unwrap()
|
|
36
60
|
|
|
37
61
|
return [artifact.node().status() for artifact in artifacts]
|
|
38
62
|
|
|
39
63
|
|
|
40
|
-
@artifacts_cli.command(help="Displays a
|
|
64
|
+
@artifacts_cli.command(help="Displays artifacts matching a pattern or a specific id")
|
|
41
65
|
@cells_cli
|
|
42
|
-
def view(
|
|
43
|
-
|
|
44
|
-
|
|
66
|
+
def view(
|
|
67
|
+
pattern: FullArtifactIdPatternArgument,
|
|
68
|
+
tags: TagOption = None,
|
|
69
|
+
) -> Iterable[Cell]:
|
|
70
|
+
artifacts = world_artifacts.list_artifacts(pattern, tags=tags).unwrap()
|
|
71
|
+
return [artifact.node().info() for artifact in artifacts]
|
|
45
72
|
|
|
46
73
|
|
|
47
74
|
@artifacts_cli.command(
|
|
@@ -63,6 +90,24 @@ def fetch(id: FullArtifactIdArgument, output: OutputPathOption = None) -> Iterab
|
|
|
63
90
|
]
|
|
64
91
|
|
|
65
92
|
|
|
93
|
+
@artifacts_cli.command(
|
|
94
|
+
help="Create a temporary file for artifact-related work and print its path. Use it to create new artifacts"
|
|
95
|
+
)
|
|
96
|
+
@cells_cli
|
|
97
|
+
def tmp(
|
|
98
|
+
slug_with_extension: str = typer.Argument(..., help="Temporary file slug with extension (example: 'draft.md').")
|
|
99
|
+
) -> Iterable[Cell]:
|
|
100
|
+
slug, extension = _parse_slug_with_extension(slug_with_extension).unwrap()
|
|
101
|
+
output = world_tmp.create_file_for_slug(slug, extension)
|
|
102
|
+
|
|
103
|
+
return [
|
|
104
|
+
operation_succeeded(
|
|
105
|
+
f"Temporary file created at '{output}'",
|
|
106
|
+
output_path=str(output),
|
|
107
|
+
)
|
|
108
|
+
]
|
|
109
|
+
|
|
110
|
+
|
|
66
111
|
@artifacts_cli.command(help="Create or replace the artifact with the contents of a file.")
|
|
67
112
|
@cells_cli
|
|
68
113
|
def update(id: FullArtifactIdArgument, input: InputPathArgument) -> Iterable[Cell]:
|
|
@@ -70,6 +115,48 @@ def update(id: FullArtifactIdArgument, input: InputPathArgument) -> Iterable[Cel
|
|
|
70
115
|
return [operation_succeeded(f"Artifact `{id}` updated from '{input}'", artifact_id=str(id), input_path=str(input))]
|
|
71
116
|
|
|
72
117
|
|
|
118
|
+
@artifacts_cli.command(help="Copy an artifact to another artifact ID (possibly across worlds).")
|
|
119
|
+
@cells_cli
|
|
120
|
+
def copy(source_id: FullArtifactIdArgument, target_id: FullArtifactIdArgument) -> Iterable[Cell]:
|
|
121
|
+
world_artifacts.copy_artifact(source_id, target_id).unwrap()
|
|
122
|
+
return [
|
|
123
|
+
operation_succeeded(
|
|
124
|
+
f"Artifact `{source_id}` copied to `{target_id}`",
|
|
125
|
+
source_id=str(source_id),
|
|
126
|
+
target_id=str(target_id),
|
|
127
|
+
)
|
|
128
|
+
]
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
@artifacts_cli.command(help="Move an artifact to another artifact ID (possibly across worlds).")
|
|
132
|
+
@cells_cli
|
|
133
|
+
def move(source_id: FullArtifactIdArgument, target_id: FullArtifactIdArgument) -> Iterable[Cell]:
|
|
134
|
+
world_artifacts.move_artifact(source_id, target_id).unwrap()
|
|
135
|
+
return [
|
|
136
|
+
operation_succeeded(
|
|
137
|
+
f"Artifact `{source_id}` moved to `{target_id}`",
|
|
138
|
+
source_id=str(source_id),
|
|
139
|
+
target_id=str(target_id),
|
|
140
|
+
)
|
|
141
|
+
]
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
@artifacts_cli.command(help="Remove artifacts matching a pattern.")
|
|
145
|
+
@cells_cli
|
|
146
|
+
def remove(
|
|
147
|
+
pattern: FullArtifactIdPatternArgument,
|
|
148
|
+
tags: TagOption = None,
|
|
149
|
+
) -> Iterable[Cell]:
|
|
150
|
+
artifacts = world_artifacts.list_artifacts(pattern, tags=tags).unwrap()
|
|
151
|
+
|
|
152
|
+
cells: builtins.list[Cell] = []
|
|
153
|
+
for artifact in artifacts:
|
|
154
|
+
world_artifacts.remove_artifact(artifact.id).unwrap()
|
|
155
|
+
cells.append(operation_succeeded(f"Artifact `{artifact.id}` removed", artifact_id=str(artifact.id)))
|
|
156
|
+
|
|
157
|
+
return cells
|
|
158
|
+
|
|
159
|
+
|
|
73
160
|
@artifacts_cli.command(help="Validate an artifact and return any validation errors.")
|
|
74
161
|
@cells_cli
|
|
75
162
|
def validate(id: FullArtifactIdArgument) -> Iterable[Cell]:
|
|
@@ -84,11 +171,11 @@ def validate(id: FullArtifactIdArgument) -> Iterable[Cell]:
|
|
|
84
171
|
help="Validate all artifacts matching a pattern (defaults to all artifacts) and return any errors."
|
|
85
172
|
)
|
|
86
173
|
@cells_cli
|
|
87
|
-
def validate_all(
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
artifacts = world_artifacts.list_artifacts(pattern).unwrap()
|
|
174
|
+
def validate_all(
|
|
175
|
+
pattern: FullArtifactIdPatternArgument = DEFAULT_ARTIFACT_PATTERN,
|
|
176
|
+
tags: TagOption = None,
|
|
177
|
+
) -> Iterable[Cell]: # noqa: CCR001
|
|
178
|
+
artifacts = world_artifacts.list_artifacts(pattern, tags=tags).unwrap()
|
|
92
179
|
|
|
93
180
|
errors = []
|
|
94
181
|
|
donna/cli/commands/sessions.py
CHANGED
|
@@ -21,12 +21,18 @@ def initialize(ctx: typer.Context) -> None:
|
|
|
21
21
|
try_initialize_donna()
|
|
22
22
|
|
|
23
23
|
|
|
24
|
-
@sessions_cli.command(help="Start a new session
|
|
24
|
+
@sessions_cli.command(help="Start a new session, reset session state, remove all session artifacts.")
|
|
25
25
|
@cells_cli
|
|
26
26
|
def start() -> Iterable[Cell]:
|
|
27
27
|
return sessions.start()
|
|
28
28
|
|
|
29
29
|
|
|
30
|
+
@sessions_cli.command(help="Reset the current session state, keeps session artifacts.")
|
|
31
|
+
@cells_cli
|
|
32
|
+
def reset() -> Iterable[Cell]:
|
|
33
|
+
return sessions.reset()
|
|
34
|
+
|
|
35
|
+
|
|
30
36
|
@sessions_cli.command(
|
|
31
37
|
name="continue",
|
|
32
38
|
help="Continue the current session and emit the next queued action request(s).",
|
|
@@ -64,12 +70,6 @@ def action_request_completed(
|
|
|
64
70
|
return sessions.complete_action_request(request_id, next_operation_id)
|
|
65
71
|
|
|
66
72
|
|
|
67
|
-
@sessions_cli.command(help="Clear the current session state.")
|
|
68
|
-
@cells_cli
|
|
69
|
-
def clear() -> Iterable[Cell]:
|
|
70
|
-
return sessions.clear()
|
|
71
|
-
|
|
72
|
-
|
|
73
73
|
app.add_typer(
|
|
74
74
|
sessions_cli,
|
|
75
75
|
name="sessions",
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import pathlib
|
|
2
|
+
from collections.abc import Iterable
|
|
3
|
+
|
|
4
|
+
import typer
|
|
5
|
+
|
|
6
|
+
from donna.cli.application import app
|
|
7
|
+
from donna.cli.types import ProjectDirArgument
|
|
8
|
+
from donna.cli.utils import cells_cli, try_initialize_donna
|
|
9
|
+
from donna.protocol.cell_shortcuts import operation_succeeded
|
|
10
|
+
from donna.protocol.cells import Cell
|
|
11
|
+
from donna.workspaces.initialization import initialize_workspace
|
|
12
|
+
|
|
13
|
+
workspaces_cli = typer.Typer()
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@workspaces_cli.callback(invoke_without_command=True)
|
|
17
|
+
def initialize_callback(ctx: typer.Context) -> None:
|
|
18
|
+
cmd = ctx.invoked_subcommand
|
|
19
|
+
|
|
20
|
+
if cmd is None:
|
|
21
|
+
return
|
|
22
|
+
|
|
23
|
+
if cmd in {"init"}:
|
|
24
|
+
return
|
|
25
|
+
|
|
26
|
+
try_initialize_donna()
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@workspaces_cli.command(help="Initialize Donna workspace.")
|
|
30
|
+
@cells_cli
|
|
31
|
+
def init(project_dir: ProjectDirArgument = None) -> Iterable[Cell]:
|
|
32
|
+
target_dir = project_dir or pathlib.Path.cwd()
|
|
33
|
+
initialize_workspace(target_dir).unwrap()
|
|
34
|
+
|
|
35
|
+
return [operation_succeeded("Workspace initialized successfully")]
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
app.add_typer(
|
|
39
|
+
workspaces_cli,
|
|
40
|
+
name="workspaces",
|
|
41
|
+
help="Initialize and manage Donna workspace.",
|
|
42
|
+
)
|
donna/cli/errors.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from donna.core import errors as core_errors
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class InternalError(core_errors.InternalError):
|
|
5
|
+
"""Base class for internal errors in donna.cli."""
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class CliError(core_errors.EnvironmentError):
|
|
9
|
+
cell_kind: str = "cli_error"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class InvalidSlugWithExtension(CliError):
|
|
13
|
+
code: str = "donna.cli.invalid_slug_with_extension"
|
|
14
|
+
message: str = "Invalid slug with extension: '{error.value}'."
|
|
15
|
+
ways_to_fix: list[str] = [
|
|
16
|
+
"Use the format '<slug>.<extension>' (for example: 'draft.md').",
|
|
17
|
+
]
|
|
18
|
+
value: str
|
donna/cli/types.py
CHANGED
|
@@ -73,14 +73,22 @@ FullArtifactIdArgument = Annotated[
|
|
|
73
73
|
]
|
|
74
74
|
|
|
75
75
|
|
|
76
|
-
|
|
77
|
-
FullArtifactIdPattern
|
|
78
|
-
typer.
|
|
76
|
+
FullArtifactIdPatternArgument = Annotated[
|
|
77
|
+
FullArtifactIdPattern,
|
|
78
|
+
typer.Argument(
|
|
79
79
|
parser=_parse_full_artifact_id_pattern,
|
|
80
80
|
help="Artifact pattern (supports '*' and '**', e.g. 'project:*' or '**:intro').",
|
|
81
81
|
),
|
|
82
82
|
]
|
|
83
83
|
|
|
84
|
+
TagOption = Annotated[
|
|
85
|
+
list[str] | None,
|
|
86
|
+
typer.Option(
|
|
87
|
+
"--tag",
|
|
88
|
+
help="Filter artifacts by tag. Repeatable.",
|
|
89
|
+
),
|
|
90
|
+
]
|
|
91
|
+
|
|
84
92
|
|
|
85
93
|
FullArtifactSectionIdArgument = Annotated[
|
|
86
94
|
FullArtifactSectionId,
|
|
@@ -125,14 +133,13 @@ OutputPathOption = Annotated[
|
|
|
125
133
|
),
|
|
126
134
|
]
|
|
127
135
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
typer.Option(
|
|
132
|
-
resolve_path=True,
|
|
136
|
+
ProjectDirArgument = Annotated[
|
|
137
|
+
pathlib.Path | None,
|
|
138
|
+
typer.Argument(
|
|
133
139
|
exists=True,
|
|
134
140
|
file_okay=False,
|
|
135
141
|
dir_okay=True,
|
|
136
|
-
|
|
142
|
+
resolve_path=True,
|
|
143
|
+
help="Optional project directory. Defaults to the current working directory.",
|
|
137
144
|
),
|
|
138
145
|
]
|
donna/cli/utils.py
CHANGED
|
@@ -9,7 +9,7 @@ from donna.core.errors import EnvironmentError
|
|
|
9
9
|
from donna.core.result import UnwrapError
|
|
10
10
|
from donna.protocol.cells import Cell
|
|
11
11
|
from donna.protocol.modes import get_cell_formatter
|
|
12
|
-
from donna.
|
|
12
|
+
from donna.workspaces.initialization import initialize_runtime
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
def output_cells(cells: Iterable[Cell]) -> None:
|
|
@@ -43,7 +43,7 @@ def cells_cli(func: Callable[P, Iterable[Cell]]) -> Callable[P, None]:
|
|
|
43
43
|
|
|
44
44
|
|
|
45
45
|
def try_initialize_donna() -> None:
|
|
46
|
-
result =
|
|
46
|
+
result = initialize_runtime()
|
|
47
47
|
|
|
48
48
|
if result.is_ok():
|
|
49
49
|
return
|
donna/core/errors.py
CHANGED
|
@@ -53,17 +53,7 @@ class ProjectDirNotFound(CoreEnvironmentError):
|
|
|
53
53
|
message: str = "Could not find a project directory containing `{error.donna_dir_name}`."
|
|
54
54
|
ways_to_fix: list[str] = [
|
|
55
55
|
"Run Donna from within a project directory that contains the donna directory.",
|
|
56
|
-
"Create the donna
|
|
57
|
-
]
|
|
58
|
-
donna_dir_name: str
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
class ProjectDirIsHome(CoreEnvironmentError):
|
|
62
|
-
code: str = "donna.core.project_dir_is_home"
|
|
63
|
-
message: str = "The discovered `{error.donna_dir_name}` directory is the home directory, not a project directory."
|
|
64
|
-
ways_to_fix: list[str] = [
|
|
65
|
-
"Run Donna from within a project directory that contains the donna directory.",
|
|
66
|
-
"Move the donna directory out of the home folder into the project root if appropriate.",
|
|
56
|
+
"Create the donna workspace via CLI command if it does not exist yet.",
|
|
67
57
|
]
|
|
68
58
|
donna_dir_name: str
|
|
69
59
|
|
donna/core/result.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import functools
|
|
4
|
-
from dataclasses import dataclass
|
|
5
4
|
from typing import Callable, Generic, ParamSpec, TypeVar, cast
|
|
6
5
|
|
|
7
6
|
from donna.core.errors import InternalError
|
|
@@ -25,10 +24,12 @@ class UnwrapErrError(ResultError):
|
|
|
25
24
|
message: str = "Called unwrap_err on an Ok value."
|
|
26
25
|
|
|
27
26
|
|
|
28
|
-
@dataclass(frozen=True, slots=True)
|
|
29
27
|
class Result(Generic[T, E]):
|
|
30
|
-
_is_ok
|
|
31
|
-
|
|
28
|
+
__slots__ = ("_is_ok", "_value")
|
|
29
|
+
|
|
30
|
+
def __init__(self, is_ok: bool, value: T | E) -> None:
|
|
31
|
+
self._is_ok = is_ok
|
|
32
|
+
self._value = value
|
|
32
33
|
|
|
33
34
|
def is_ok(self) -> bool:
|
|
34
35
|
return self._is_ok
|
|
@@ -82,10 +83,6 @@ def Err(error: E) -> Result[T, E]:
|
|
|
82
83
|
return Result(False, error)
|
|
83
84
|
|
|
84
85
|
|
|
85
|
-
def ok(result: Result[T, E]) -> bool:
|
|
86
|
-
return result.is_ok()
|
|
87
|
-
|
|
88
|
-
|
|
89
86
|
def unwrap_to_error(func: Callable[P, Result[T, E]]) -> Callable[P, Result[T, E]]:
|
|
90
87
|
|
|
91
88
|
@functools.wraps(func)
|
donna/core/utils.py
CHANGED
|
@@ -31,7 +31,4 @@ def discover_project_dir(donna_dir_name: str) -> Result[pathlib.Path, core_error
|
|
|
31
31
|
if donna_dir is None:
|
|
32
32
|
return Err([core_errors.ProjectDirNotFound(donna_dir_name=donna_dir_name)])
|
|
33
33
|
|
|
34
|
-
if donna_dir == donna_home_dir(donna_dir_name):
|
|
35
|
-
return Err([core_errors.ProjectDirIsHome(donna_dir_name=donna_dir_name)])
|
|
36
|
-
|
|
37
34
|
return Ok(donna_dir)
|
donna/lib/__init__.py
CHANGED
|
@@ -3,9 +3,11 @@
|
|
|
3
3
|
from donna.primitives.artifacts.specification import Specification, Text
|
|
4
4
|
from donna.primitives.artifacts.workflow import Workflow
|
|
5
5
|
from donna.primitives.directives.goto import GoTo
|
|
6
|
+
from donna.primitives.directives.list import List
|
|
6
7
|
from donna.primitives.directives.task_variable import TaskVariable
|
|
7
8
|
from donna.primitives.directives.view import View
|
|
8
9
|
from donna.primitives.operations.finish_workflow import FinishWorkflow
|
|
10
|
+
from donna.primitives.operations.output import Output
|
|
9
11
|
from donna.primitives.operations.request_action import RequestAction
|
|
10
12
|
from donna.primitives.operations.run_script import RunScript
|
|
11
13
|
|
|
@@ -14,8 +16,10 @@ workflow = Workflow()
|
|
|
14
16
|
text = Text()
|
|
15
17
|
request_action = RequestAction()
|
|
16
18
|
finish = FinishWorkflow()
|
|
19
|
+
output = Output()
|
|
17
20
|
run_script = RunScript()
|
|
18
21
|
|
|
19
22
|
view = View(analyze_id="view")
|
|
23
|
+
list = List(analyze_id="list")
|
|
20
24
|
goto = GoTo(analyze_id="goto")
|
|
21
25
|
task_variable = TaskVariable(analyze_id="task_variable")
|
donna/lib/sources.py
CHANGED
donna/lib/worlds.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Shared world constructor instances for default configuration."""
|
|
2
2
|
|
|
3
|
-
from donna.
|
|
4
|
-
from donna.
|
|
3
|
+
from donna.workspaces.worlds.filesystem import FilesystemWorldConstructor
|
|
4
|
+
from donna.workspaces.worlds.python import PythonWorldConstructor
|
|
5
5
|
|
|
6
6
|
filesystem = FilesystemWorldConstructor()
|
|
7
7
|
python = PythonWorldConstructor()
|
donna/machine/action_requests.py
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import textwrap
|
|
2
2
|
|
|
3
|
-
import pydantic
|
|
4
|
-
|
|
5
3
|
from donna.core.entities import BaseEntity
|
|
6
4
|
from donna.domain.ids import ActionRequestId, FullArtifactSectionId
|
|
7
5
|
from donna.protocol.cells import Cell
|
|
@@ -13,9 +11,6 @@ class ActionRequest(BaseEntity):
|
|
|
13
11
|
request: str
|
|
14
12
|
operation_id: FullArtifactSectionId
|
|
15
13
|
|
|
16
|
-
# TODO: we may want to make queue items frozen later
|
|
17
|
-
model_config = pydantic.ConfigDict(frozen=False)
|
|
18
|
-
|
|
19
14
|
@classmethod
|
|
20
15
|
def build(cls, request: str, operation_id: FullArtifactSectionId) -> "ActionRequest":
|
|
21
16
|
return cls(
|
donna/machine/artifacts.py
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
from typing import TYPE_CHECKING, Any
|
|
2
2
|
|
|
3
|
+
import pydantic
|
|
4
|
+
|
|
3
5
|
from donna.core.entities import BaseEntity
|
|
4
6
|
from donna.core.errors import ErrorsList
|
|
5
7
|
from donna.core.result import Err, Ok, Result, unwrap_to_error
|
|
@@ -13,12 +15,13 @@ from donna.protocol.cells import Cell
|
|
|
13
15
|
from donna.protocol.nodes import Node
|
|
14
16
|
|
|
15
17
|
if TYPE_CHECKING:
|
|
16
|
-
from donna.
|
|
18
|
+
from donna.workspaces.artifacts import ArtifactRenderContext
|
|
17
19
|
|
|
18
20
|
|
|
19
21
|
class ArtifactSectionConfig(BaseEntity):
|
|
20
22
|
id: ArtifactSectionId
|
|
21
23
|
kind: PythonImportPath
|
|
24
|
+
tags: list[str] = pydantic.Field(default_factory=list)
|
|
22
25
|
|
|
23
26
|
|
|
24
27
|
class ArtifactSectionMeta(BaseEntity):
|
|
@@ -32,6 +35,7 @@ class ArtifactSection(BaseEntity):
|
|
|
32
35
|
kind: PythonImportPath
|
|
33
36
|
title: str
|
|
34
37
|
description: str
|
|
38
|
+
tags: list[str] = pydantic.Field(default_factory=list)
|
|
35
39
|
primary: bool = False
|
|
36
40
|
|
|
37
41
|
meta: ArtifactSectionMeta
|
|
@@ -138,12 +142,12 @@ class ArtifactNode(Node):
|
|
|
138
142
|
return primary_section_result.unwrap_err()[0].node().status()
|
|
139
143
|
|
|
140
144
|
primary_section = primary_section_result.unwrap()
|
|
141
|
-
return Cell.
|
|
145
|
+
return Cell.build_markdown(
|
|
142
146
|
kind="artifact_status",
|
|
143
147
|
artifact_id=str(self._artifact.id),
|
|
144
148
|
artifact_kind=str(primary_section.kind),
|
|
145
149
|
artifact_title=primary_section.title,
|
|
146
|
-
|
|
150
|
+
content=primary_section.description,
|
|
147
151
|
)
|
|
148
152
|
|
|
149
153
|
def info(self) -> Cell:
|
|
@@ -161,8 +165,6 @@ class ArtifactNode(Node):
|
|
|
161
165
|
content="\n".join(blocks_result.unwrap()),
|
|
162
166
|
artifact_id=str(self._artifact.id),
|
|
163
167
|
artifact_kind=str(primary_section.kind),
|
|
164
|
-
artifact_title=primary_section.title,
|
|
165
|
-
artifact_description=primary_section.description,
|
|
166
168
|
)
|
|
167
169
|
|
|
168
170
|
def components(self) -> list["Node"]:
|
|
@@ -191,7 +193,7 @@ class ArtifactSectionNode(Node):
|
|
|
191
193
|
def resolve(
|
|
192
194
|
target_id: FullArtifactSectionId, render_context: "ArtifactRenderContext"
|
|
193
195
|
) -> Result[ArtifactSection, ErrorsList]:
|
|
194
|
-
from donna.
|
|
196
|
+
from donna.workspaces import artifacts as world_artifacts
|
|
195
197
|
|
|
196
198
|
artifact = world_artifacts.load_artifact(target_id.full_artifact_id, render_context).unwrap()
|
|
197
199
|
|
donna/machine/primitives.py
CHANGED
|
@@ -14,10 +14,10 @@ if TYPE_CHECKING:
|
|
|
14
14
|
from donna.machine.artifacts import Artifact, ArtifactSection
|
|
15
15
|
from donna.machine.changes import Change
|
|
16
16
|
from donna.machine.tasks import Task, WorkUnit
|
|
17
|
-
from donna.
|
|
18
|
-
from donna.
|
|
19
|
-
from donna.
|
|
20
|
-
from donna.
|
|
17
|
+
from donna.workspaces.config import SourceConfig as SourceConfigModel
|
|
18
|
+
from donna.workspaces.config import WorldConfig
|
|
19
|
+
from donna.workspaces.sources.base import SourceConfig as SourceConfigValue
|
|
20
|
+
from donna.workspaces.worlds.base import World
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
# TODO: Currently is is a kind of God interface. It is convinient for now.
|
donna/machine/sessions.py
CHANGED
|
@@ -9,10 +9,10 @@ from donna.machine.operations import OperationMeta
|
|
|
9
9
|
from donna.machine.state import ConsistentState, MutableState
|
|
10
10
|
from donna.protocol.cell_shortcuts import operation_succeeded
|
|
11
11
|
from donna.protocol.cells import Cell
|
|
12
|
-
from donna.
|
|
13
|
-
from donna.
|
|
14
|
-
from donna.
|
|
15
|
-
from donna.
|
|
12
|
+
from donna.workspaces import artifacts
|
|
13
|
+
from donna.workspaces import tmp as world_tmp
|
|
14
|
+
from donna.workspaces.config import config
|
|
15
|
+
from donna.workspaces.worlds.base import World
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
def _errors_to_cells(errors: ErrorsList) -> list[Cell]:
|
|
@@ -90,6 +90,14 @@ def start() -> list[Cell]:
|
|
|
90
90
|
return [operation_succeeded("Started new session.")]
|
|
91
91
|
|
|
92
92
|
|
|
93
|
+
def reset() -> list[Cell]:
|
|
94
|
+
save_result = _save_state(MutableState.build().freeze())
|
|
95
|
+
if save_result.is_err():
|
|
96
|
+
return _errors_to_cells(save_result.unwrap_err())
|
|
97
|
+
|
|
98
|
+
return [operation_succeeded("Session state reset.")]
|
|
99
|
+
|
|
100
|
+
|
|
93
101
|
def clear() -> list[Cell]:
|
|
94
102
|
world_tmp.clear()
|
|
95
103
|
session_result = _session()
|
donna/machine/state.py
CHANGED
|
@@ -118,8 +118,8 @@ class MutableState(BaseState):
|
|
|
118
118
|
self.started = True
|
|
119
119
|
|
|
120
120
|
def add_action_request(self, action_request: ActionRequest) -> None:
|
|
121
|
-
action_request.id
|
|
122
|
-
self.action_requests.append(
|
|
121
|
+
full_request = action_request.replace(id=self.next_action_request_id())
|
|
122
|
+
self.action_requests.append(full_request)
|
|
123
123
|
|
|
124
124
|
def add_work_unit(self, work_unit: WorkUnit) -> None:
|
|
125
125
|
self.work_units.append(work_unit)
|
donna/machine/tasks.py
CHANGED
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
import copy
|
|
2
|
-
import sys
|
|
3
2
|
from typing import TYPE_CHECKING, Any
|
|
4
3
|
|
|
5
|
-
import pydantic
|
|
6
|
-
|
|
7
4
|
from donna.core.entities import BaseEntity
|
|
8
5
|
from donna.core.errors import ErrorsList
|
|
9
6
|
from donna.core.result import Ok, Result, unwrap_to_error
|
|
10
7
|
from donna.domain.ids import FullArtifactSectionId, TaskId, WorkUnitId
|
|
11
8
|
from donna.protocol.cells import Cell
|
|
12
|
-
from donna.protocol.
|
|
9
|
+
from donna.protocol.utils import instant_output
|
|
13
10
|
|
|
14
11
|
if TYPE_CHECKING:
|
|
15
12
|
from donna.machine.changes import Change
|
|
@@ -19,9 +16,6 @@ class Task(BaseEntity):
|
|
|
19
16
|
id: TaskId
|
|
20
17
|
context: dict[str, Any]
|
|
21
18
|
|
|
22
|
-
# TODO: we may want to make queue items frozen later
|
|
23
|
-
model_config = pydantic.ConfigDict(frozen=False)
|
|
24
|
-
|
|
25
19
|
@classmethod
|
|
26
20
|
def build(cls, id: TaskId) -> "Task":
|
|
27
21
|
return Task(
|
|
@@ -61,8 +55,8 @@ class WorkUnit(BaseEntity):
|
|
|
61
55
|
def run(self, task: Task) -> Result[list["Change"], ErrorsList]:
|
|
62
56
|
from donna.machine import artifacts as machine_artifacts
|
|
63
57
|
from donna.machine.primitives import resolve_primitive
|
|
64
|
-
from donna.
|
|
65
|
-
from donna.
|
|
58
|
+
from donna.workspaces.artifacts import ArtifactRenderContext
|
|
59
|
+
from donna.workspaces.templates import RenderMode
|
|
66
60
|
|
|
67
61
|
render_context = ArtifactRenderContext(
|
|
68
62
|
primary_mode=RenderMode.execute,
|
|
@@ -72,17 +66,9 @@ class WorkUnit(BaseEntity):
|
|
|
72
66
|
operation = machine_artifacts.resolve(self.operation_id, render_context).unwrap()
|
|
73
67
|
operation_kind = resolve_primitive(operation.kind).unwrap()
|
|
74
68
|
|
|
75
|
-
##########################
|
|
76
|
-
# We log each operation here to help agent display the progress to the user
|
|
77
|
-
# TODO: not a good solution from the agent perspective
|
|
78
|
-
# let's hope there will some protocol appear that helps with that later
|
|
79
|
-
# TODO: not so good place for and way of logging, should do smth with that
|
|
80
69
|
log_message = f"{self.operation_id}: {operation.title}"
|
|
81
70
|
log_cell = Cell.build(kind="donna_log", media_type="text/plain", content=log_message)
|
|
82
|
-
|
|
83
|
-
sys.stdout.buffer.write(formatter.format_log(log_cell, single_mode=True) + b"\n\n")
|
|
84
|
-
sys.stdout.buffer.flush()
|
|
85
|
-
##########################
|
|
71
|
+
instant_output([log_cell])
|
|
86
72
|
|
|
87
73
|
changes = list(operation_kind.execute_section(task, self, operation))
|
|
88
74
|
|
donna/machine/templates.py
CHANGED
|
@@ -28,11 +28,12 @@ class Directive(Primitive, ABC):
|
|
|
28
28
|
self,
|
|
29
29
|
context: Context,
|
|
30
30
|
*argv: Any,
|
|
31
|
+
**kwargs: Any,
|
|
31
32
|
) -> Result[Any, ErrorsList]:
|
|
32
|
-
from donna.
|
|
33
|
+
from donna.workspaces import templates as world_templates
|
|
33
34
|
|
|
34
35
|
render_mode = context["render_mode"]
|
|
35
|
-
arguments_result = self._prepare_arguments(context, *argv)
|
|
36
|
+
arguments_result = self._prepare_arguments(context, *argv, **kwargs)
|
|
36
37
|
if arguments_result.is_err():
|
|
37
38
|
return arguments_result
|
|
38
39
|
|
|
@@ -52,6 +53,7 @@ class Directive(Primitive, ABC):
|
|
|
52
53
|
self,
|
|
53
54
|
context: Context,
|
|
54
55
|
*argv: Any,
|
|
56
|
+
**kwargs: Any,
|
|
55
57
|
) -> PreparedDirectiveResult:
|
|
56
58
|
return Ok(argv)
|
|
57
59
|
|