heinzel-example 0.4.0__tar.gz → 0.5.2__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.
- heinzel_example-0.5.2/CHANGELOG.md +21 -0
- heinzel_example-0.5.2/PKG-INFO +104 -0
- heinzel_example-0.5.2/README.md +83 -0
- heinzel_example-0.5.2/docs/SCREENSHOTS.md +10 -0
- heinzel_example-0.5.2/docs/SCREENSHOT_STORY.md +43 -0
- heinzel_example-0.5.2/docs/assets/cli.png +0 -0
- heinzel_example-0.5.2/docs/assets/screenshots/capture.json +102 -0
- heinzel_example-0.5.2/docs/assets/screenshots/greeting-cli.png +0 -0
- heinzel_example-0.5.2/docs/assets/screenshots/greeting-cli.txt +1 -0
- heinzel_example-0.5.2/docs/assets/screenshots/greeting-terminal.png +0 -0
- heinzel_example-0.5.2/docs/assets/screenshots/greeting-terminal.txt +48 -0
- heinzel_example-0.5.2/docs/assets/screenshots/index.html +1 -0
- heinzel_example-0.5.2/docs/assets/screenshots/inspector.png +0 -0
- heinzel_example-0.5.2/docs/assets/screenshots/inspector.txt +41 -0
- heinzel_example-0.5.2/docs/assets/screenshots/plugin-notice.png +0 -0
- heinzel_example-0.5.2/docs/assets/screenshots/plugin-notice.txt +57 -0
- heinzel_example-0.5.2/docs/assets/screenshots/sample-json.png +0 -0
- heinzel_example-0.5.2/docs/assets/screenshots/sample-json.txt +1 -0
- heinzel_example-0.5.2/docs/assets/screenshots/source-story.md +43 -0
- heinzel_example-0.5.2/docs/assets/screenshots/widget-and-status.png +0 -0
- heinzel_example-0.5.2/docs/assets/screenshots/widget-and-status.txt +40 -0
- heinzel_example-0.5.2/docs/assets/ui.png +0 -0
- heinzel_example-0.5.2/docs/screenshot-definition.json +7 -0
- heinzel_example-0.5.2/docs/screenshot_fixture.py +23 -0
- heinzel_example-0.5.2/docs/screenshots.toml +96 -0
- {heinzel_example-0.4.0 → heinzel_example-0.5.2}/plugin-lock.json +3 -1
- {heinzel_example-0.4.0 → heinzel_example-0.5.2}/pyproject.toml +40 -1
- {heinzel_example-0.4.0 → heinzel_example-0.5.2}/requirements.lock +23 -3
- {heinzel_example-0.4.0 → heinzel_example-0.5.2}/src/heinzel_example/__init__.py +9 -4
- {heinzel_example-0.4.0 → heinzel_example-0.5.2}/src/heinzel_example/views/index.js +3 -3
- {heinzel_example-0.4.0 → heinzel_example-0.5.2}/tests/contributions_test.py +13 -1
- heinzel_example-0.4.0/CHANGELOG.md +0 -8
- heinzel_example-0.4.0/PKG-INFO +0 -59
- heinzel_example-0.4.0/README.md +0 -38
- {heinzel_example-0.4.0 → heinzel_example-0.5.2}/.gitignore +0 -0
- {heinzel_example-0.4.0 → heinzel_example-0.5.2}/LICENSE +0 -0
- {heinzel_example-0.4.0 → heinzel_example-0.5.2}/src/heinzel_example/_models.py +0 -0
- {heinzel_example-0.4.0 → heinzel_example-0.5.2}/src/heinzel_example/_service.py +0 -0
- {heinzel_example-0.4.0 → heinzel_example-0.5.2}/src/heinzel_example/hello/__init__.py +0 -0
- {heinzel_example-0.4.0 → heinzel_example-0.5.2}/src/heinzel_example/py.typed +0 -0
- {heinzel_example-0.4.0 → heinzel_example-0.5.2}/tests/acceptance/install_test.py +0 -0
- {heinzel_example-0.4.0 → heinzel_example-0.5.2}/tests/conftest.py +0 -0
- {heinzel_example-0.4.0 → heinzel_example-0.5.2}/tests/integration/cli_test.py +0 -0
- {heinzel_example-0.4.0 → heinzel_example-0.5.2}/tests/unit/service_test.py +0 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.5.2
|
|
4
|
+
|
|
5
|
+
Relock opentelemetry-api to 1.45.2 (CVE-2026-126360).
|
|
6
|
+
|
|
7
|
+
## 0.5.1
|
|
8
|
+
|
|
9
|
+
Relock for Heinzel Core 0.9.40 (its AI extra adds pyjwt) and refresh the gallery.
|
|
10
|
+
|
|
11
|
+
## 0.5.0
|
|
12
|
+
|
|
13
|
+
Add a footer icon that opens an Example pane showing the value 42 big, the same value as the Today widget. The README
|
|
14
|
+
explains how a plugin contributes a footer pane.
|
|
15
|
+
|
|
16
|
+
## 0.4.0
|
|
17
|
+
|
|
18
|
+
Move this plugin to its independent repository project for the Heinzel 0.9 plugin contract.
|
|
19
|
+
Own its dependencies, tests and artifacts; consume public contracts without concrete provider dependencies.
|
|
20
|
+
|
|
21
|
+
Earlier history: the heinzel repository before 0.9.
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: heinzel-example
|
|
3
|
+
Version: 0.5.2
|
|
4
|
+
Summary: Show how a Heinzelmännchen plugin is built.
|
|
5
|
+
Project-URL: Source, https://github.com/helmut-hoffer-von-ankershoffen/heinzel-plugins/tree/main/plugins/heinzel-example
|
|
6
|
+
Project-URL: Changelog, https://github.com/helmut-hoffer-von-ankershoffen/heinzel-plugins/blob/main/plugins/heinzel-example/CHANGELOG.md
|
|
7
|
+
Project-URL: Issues, https://github.com/helmut-hoffer-von-ankershoffen/heinzel-plugins/issues
|
|
8
|
+
Author-email: Helmut Hoffer von Ankershoffen <helmuthva@gmail.com>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: heinzel,heinzel-plugin,heinzelmaennchen
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Operating System :: MacOS
|
|
15
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Typing :: Typed
|
|
18
|
+
Requires-Python: >=3.12
|
|
19
|
+
Requires-Dist: heinzel<0.10,>=0.9.1
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
|
|
22
|
+
# heinzel-example
|
|
23
|
+
|
|
24
|
+
Show how a Heinzelmännchen plugin is built: one module with an operation, settings, a health check and a submodule.
|
|
25
|
+
|
|
26
|
+
A plugin for [Heinzelmännchen](https://github.com/helmut-hoffer-von-ankershoffen/heinzel), the open-source, AI-driven
|
|
27
|
+
operating system for product development teams. It lives in
|
|
28
|
+
[heinzel-plugins](https://github.com/helmut-hoffer-von-ankershoffen/heinzel-plugins).
|
|
29
|
+
|
|
30
|
+
## Install
|
|
31
|
+
|
|
32
|
+
Start Heinzelmännchen with `uvx heinzel@latest`. In another terminal, add this plugin:
|
|
33
|
+
|
|
34
|
+
```sh
|
|
35
|
+
hz system plugin add example --confirm
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
`hz system update` updates the app and its plugins; `hz system plugin remove heinzel-example` removes this one.
|
|
39
|
+
|
|
40
|
+
## Use
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
hz example info # this plugin, its version and the Heinzelmännchen it runs on
|
|
44
|
+
hz example hello --name Ada # a submodule collapsed into a command
|
|
45
|
+
hz example info --json # every command speaks JSON, for scripts and agents
|
|
46
|
+
hz system info # includes a section contributed by this plugin
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Develop
|
|
50
|
+
|
|
51
|
+
From the repository root: `make check-fast NAME=example` runs this plugin's edit loop; `make check NAME=example`
|
|
52
|
+
runs its full checks. `make build NAME=example` and `make acceptance NAME=example` verify its installed artifact.
|
|
53
|
+
The modules live in
|
|
54
|
+
`src/heinzel_example/`; read the root [AGENTS.md](../../AGENTS.md) before changing them.
|
|
55
|
+
|
|
56
|
+
## Footer pane
|
|
57
|
+
|
|
58
|
+
The example is also the teaching example for a footer icon that opens a pane. Three contributions in
|
|
59
|
+
`src/heinzel_example/__init__.py` do it, with no core change:
|
|
60
|
+
|
|
61
|
+
- `@module.status(source="sample", slots={"footer": True, "sidebar": True})` returns a `StatusItem` with an `icon`, a
|
|
62
|
+
`detail` line (the tooltip, "Example") and `effect=Navigate(path="/?panel=example:inspector")`, the click target.
|
|
63
|
+
- `module.view(..., name="inspector", title="Example", source="sample")` is the pane that target opens; its
|
|
64
|
+
`views/index.js` shows the value (42, the same `sample` operation as the Today widget) big. A pane is content, then a
|
|
65
|
+
divider and a bottom action row only when it has actions; this one has none.
|
|
66
|
+
- `tests/contributions_test.py` asserts the slots, icon, tooltip, target and view.
|
|
67
|
+
|
|
68
|
+
Development and release commands: [repository guide](../../README.md).
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
<!-- screenshots:start -->
|
|
72
|
+
## Screenshots
|
|
73
|
+
|
|
74
|
+
<img src="docs/assets/screenshots/widget-and-status.png" alt="Demo data: the constant 42 appears in both the Today widget and sidebar status." width="960">
|
|
75
|
+
|
|
76
|
+
Demo data: the constant 42 appears in both the Today widget and sidebar status.
|
|
77
|
+
|
|
78
|
+
<img src="docs/assets/screenshots/inspector.png" alt="Demo data: open the plugin-owned inspector to see the same constant value, 42." width="960">
|
|
79
|
+
|
|
80
|
+
Demo data: open the plugin-owned inspector to see the same constant value, 42.
|
|
81
|
+
|
|
82
|
+
<img src="docs/assets/screenshots/greeting-terminal.png" alt="Demo data: greet fictional Mira with structured JSON in the app's native terminal." width="960">
|
|
83
|
+
|
|
84
|
+
Demo data: greet fictional Mira with structured JSON in the app's native terminal.
|
|
85
|
+
|
|
86
|
+
<img src="docs/assets/screenshots/plugin-notice.png" alt="Demo data: a seeded Example is ready notice appears in the shared in-app notification panel." width="960">
|
|
87
|
+
|
|
88
|
+
Demo data: a seeded Example is ready notice appears in the shared in-app notification panel.
|
|
89
|
+
|
|
90
|
+
<details>
|
|
91
|
+
<summary>Command line</summary>
|
|
92
|
+
|
|
93
|
+
<img src="docs/assets/screenshots/greeting-cli.png" alt="Demo data: the typed hello operation greets fictional Mira from the CLI." width="960">
|
|
94
|
+
|
|
95
|
+
Demo data: the typed hello operation greets fictional Mira from the CLI.
|
|
96
|
+
|
|
97
|
+
<img src="docs/assets/screenshots/sample-json.png" alt="Demo data: sample returns 42 as JSON, the same constant used by the widget, status and inspector." width="960">
|
|
98
|
+
|
|
99
|
+
Demo data: sample returns 42 as JSON, the same constant used by the widget, status and inspector.
|
|
100
|
+
|
|
101
|
+
</details>
|
|
102
|
+
|
|
103
|
+
[Open the screenshot gallery](docs/assets/screenshots/index.html).
|
|
104
|
+
<!-- screenshots:end -->
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# heinzel-example
|
|
2
|
+
|
|
3
|
+
Show how a Heinzelmännchen plugin is built: one module with an operation, settings, a health check and a submodule.
|
|
4
|
+
|
|
5
|
+
A plugin for [Heinzelmännchen](https://github.com/helmut-hoffer-von-ankershoffen/heinzel), the open-source, AI-driven
|
|
6
|
+
operating system for product development teams. It lives in
|
|
7
|
+
[heinzel-plugins](https://github.com/helmut-hoffer-von-ankershoffen/heinzel-plugins).
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
Start Heinzelmännchen with `uvx heinzel@latest`. In another terminal, add this plugin:
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
hz system plugin add example --confirm
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
`hz system update` updates the app and its plugins; `hz system plugin remove heinzel-example` removes this one.
|
|
18
|
+
|
|
19
|
+
## Use
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
hz example info # this plugin, its version and the Heinzelmännchen it runs on
|
|
23
|
+
hz example hello --name Ada # a submodule collapsed into a command
|
|
24
|
+
hz example info --json # every command speaks JSON, for scripts and agents
|
|
25
|
+
hz system info # includes a section contributed by this plugin
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Develop
|
|
29
|
+
|
|
30
|
+
From the repository root: `make check-fast NAME=example` runs this plugin's edit loop; `make check NAME=example`
|
|
31
|
+
runs its full checks. `make build NAME=example` and `make acceptance NAME=example` verify its installed artifact.
|
|
32
|
+
The modules live in
|
|
33
|
+
`src/heinzel_example/`; read the root [AGENTS.md](../../AGENTS.md) before changing them.
|
|
34
|
+
|
|
35
|
+
## Footer pane
|
|
36
|
+
|
|
37
|
+
The example is also the teaching example for a footer icon that opens a pane. Three contributions in
|
|
38
|
+
`src/heinzel_example/__init__.py` do it, with no core change:
|
|
39
|
+
|
|
40
|
+
- `@module.status(source="sample", slots={"footer": True, "sidebar": True})` returns a `StatusItem` with an `icon`, a
|
|
41
|
+
`detail` line (the tooltip, "Example") and `effect=Navigate(path="/?panel=example:inspector")`, the click target.
|
|
42
|
+
- `module.view(..., name="inspector", title="Example", source="sample")` is the pane that target opens; its
|
|
43
|
+
`views/index.js` shows the value (42, the same `sample` operation as the Today widget) big. A pane is content, then a
|
|
44
|
+
divider and a bottom action row only when it has actions; this one has none.
|
|
45
|
+
- `tests/contributions_test.py` asserts the slots, icon, tooltip, target and view.
|
|
46
|
+
|
|
47
|
+
Development and release commands: [repository guide](../../README.md).
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
<!-- screenshots:start -->
|
|
51
|
+
## Screenshots
|
|
52
|
+
|
|
53
|
+
<img src="docs/assets/screenshots/widget-and-status.png" alt="Demo data: the constant 42 appears in both the Today widget and sidebar status." width="960">
|
|
54
|
+
|
|
55
|
+
Demo data: the constant 42 appears in both the Today widget and sidebar status.
|
|
56
|
+
|
|
57
|
+
<img src="docs/assets/screenshots/inspector.png" alt="Demo data: open the plugin-owned inspector to see the same constant value, 42." width="960">
|
|
58
|
+
|
|
59
|
+
Demo data: open the plugin-owned inspector to see the same constant value, 42.
|
|
60
|
+
|
|
61
|
+
<img src="docs/assets/screenshots/greeting-terminal.png" alt="Demo data: greet fictional Mira with structured JSON in the app's native terminal." width="960">
|
|
62
|
+
|
|
63
|
+
Demo data: greet fictional Mira with structured JSON in the app's native terminal.
|
|
64
|
+
|
|
65
|
+
<img src="docs/assets/screenshots/plugin-notice.png" alt="Demo data: a seeded Example is ready notice appears in the shared in-app notification panel." width="960">
|
|
66
|
+
|
|
67
|
+
Demo data: a seeded Example is ready notice appears in the shared in-app notification panel.
|
|
68
|
+
|
|
69
|
+
<details>
|
|
70
|
+
<summary>Command line</summary>
|
|
71
|
+
|
|
72
|
+
<img src="docs/assets/screenshots/greeting-cli.png" alt="Demo data: the typed hello operation greets fictional Mira from the CLI." width="960">
|
|
73
|
+
|
|
74
|
+
Demo data: the typed hello operation greets fictional Mira from the CLI.
|
|
75
|
+
|
|
76
|
+
<img src="docs/assets/screenshots/sample-json.png" alt="Demo data: sample returns 42 as JSON, the same constant used by the widget, status and inspector." width="960">
|
|
77
|
+
|
|
78
|
+
Demo data: sample returns 42 as JSON, the same constant used by the widget, status and inspector.
|
|
79
|
+
|
|
80
|
+
</details>
|
|
81
|
+
|
|
82
|
+
[Open the screenshot gallery](docs/assets/screenshots/index.html).
|
|
83
|
+
<!-- screenshots:end -->
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Screenshot gallery
|
|
2
|
+
|
|
3
|
+
From the collection root, run `make screenshots NAME=heinzel-example OPEN=1`.
|
|
4
|
+
Review the [contact sheet](assets/screenshots/index.html) before committing.
|
|
5
|
+
The [scene plan](screenshots.toml) describes the real UI and CLI captures.
|
|
6
|
+
`make screenshots-check NAME=heinzel-example` verifies freshness offline.
|
|
7
|
+
|
|
8
|
+
Captures use a temporary fictional profile without connected accounts. The generated
|
|
9
|
+
[manifest](assets/screenshots/capture.json) records the SDK version and input/image digests.
|
|
10
|
+
See the [author guide](../../../docs/SCREENSHOT_AUTHORING.md) for human and agent commands.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
## Audience
|
|
2
|
+
|
|
3
|
+
Plugin authors evaluating a small, working reference for Heinzelmännchen extensions.
|
|
4
|
+
|
|
5
|
+
## Outcome
|
|
6
|
+
|
|
7
|
+
See one value move from an operation into the Today widget, sidebar status, and an inspector pane; then see a typed greeting and a seeded notification. The examples show integration points to explore, not a production business workflow.
|
|
8
|
+
|
|
9
|
+
## Scenes
|
|
10
|
+
|
|
11
|
+
1. **Widget and status, light:** The Today widget and sidebar both show the sample value, 42. `src/heinzel_example/__init__.py` declares `sample`, `@module.widget(source="sample")`, and `@module.status(source="sample", slots={"footer": True, "sidebar": True})`.
|
|
12
|
+
2. **Inspector, dark:** The real Example pane displays 42. `module.nav`, `module.action`, and the status effect navigate to `/?panel=example:inspector`; `module.view(..., name="inspector", source="sample")` owns that pane, rendered by `src/heinzel_example/views/index.js`.
|
|
13
|
+
3. **Greeting in the app terminal:** Run the fictional Mira greeting with JSON output. This is a native terminal result, not a feature UI. `src/heinzel_example/hello/__init__.py` declares the collapsed `hello` operation; `_service.py` constructs the greeting.
|
|
14
|
+
4. **Notification:** Open the shared notification panel to see the seeded “Example is ready” notice. The `notify` operation in `src/heinzel_example/__init__.py` emits it; `docs/screenshot_fixture.py` seeds it in the isolated capture profile.
|
|
15
|
+
5. **Greeting CLI:** Show the same fictional greeting as a direct CLI result.
|
|
16
|
+
6. **Sample JSON CLI:** Show the source value as structured output, connecting the CLI to the widget and inspector.
|
|
17
|
+
|
|
18
|
+
## Fictional fixtures and presentation
|
|
19
|
+
|
|
20
|
+
Use the existing `docs/screenshot_fixture.py` bootstrap and its isolated profile; do not create fixture files. Mira is fictional, and 42 is the actual constant returned by `sample`. The notice is seeded demonstration data. Captions identify demo data.
|
|
21
|
+
|
|
22
|
+
Normal presentation fictionalization is explicitly limited to verified owning-interpreter paths becoming `/demo-profile/.venv`, and only the verified whole hostname detail in the genuine Doctor row becoming `demo-host`. These mappings change no SDK health status or remaining detail and establish no privacy acceptance. Unknown identities still fail, and independent review must inspect every image and transcript.
|
|
23
|
+
|
|
24
|
+
## Privacy pitfalls
|
|
25
|
+
|
|
26
|
+
The bootstrap disables native, Doctor, and release notifications and invokes the plugin notice in an isolated profile; it does not by itself prove that captures contain no personal information. Inspect paths, hostnames, account names, notifications, timestamps, terminal output, and other incidental content. Do not conceal unknown identities with assumed substitutions.
|
|
27
|
+
|
|
28
|
+
## Source-bound UI surface inventory
|
|
29
|
+
|
|
30
|
+
- **Plugin entrypoint:** `pyproject.toml` declares `heinzel.modules` entry `example = "heinzel_example"`. `src/heinzel_example/__init__.py` declares the root `Module("example", ...)`; `src/heinzel_example/hello/__init__.py` declares the discovered `Module("hello", ...)` submodule.
|
|
31
|
+
- **Genuine feature UI:** The Core-rendered Today metric and footer/sidebar status come from the widget and status declarations. The plugin-owned inspector is a real view at the declared panel target, implemented in `src/heinzel_example/views/index.js`. Its loading state and value are rendered using SDK React; it declares no action row. The same actual value across these surfaces is intentional, but the overview and inspector must remain visually and functionally distinct captures.
|
|
32
|
+
- **Other Core-rendered contributions:** `module.action` and `module.nav` open the inspector. `notify` contributes a plugin notice to the shared notification UI. `module.settings(ExampleSettings)` registers the `greeting` setting in `src/heinzel_example/_models.py`; `@module.info` contributes details to system info. The non-read-only `notify` operation declares an ordinary confirmation. These declarations can give rise to generic Core surfaces, but their precise layouts are not supplied here and must not be invented. No channel or setup contribution is declared in the supplied entrypoints.
|
|
33
|
+
- **Operations and terminal:** Root operations are `info`, `sample`, and `notify`; the hello submodule declares `hello`. CLI output is genuine terminal output, including when displayed in the app terminal, and is not evidence of a feature UI. `README.md` documents `hz example hello`, `hz example info`, JSON output, and system info; the source also declares `sample` and `notify`.
|
|
34
|
+
- **External provider UI:** None is declared in the supplied plugin source. No external provider screen is needed for this story.
|
|
35
|
+
- **Unresolved evidence:** `README.md` describes a health check, but the supplied module declarations contain no explicit health-check contribution; do not invent one. The README also references `tests/contributions_test.py`, which is not among the supplied files. Core implementation and the screenshot author guide are not supplied, so generic surface details and capture behavior require observation during explicit capture. The existing plan is preserved because it already covers two real feature UI scenes, a notice, and useful CLI results.
|
|
36
|
+
|
|
37
|
+
## Acceptance criteria
|
|
38
|
+
|
|
39
|
+
- Capture all six planned scenes from the real app or CLI with the existing bootstrap, and confirm the light overview and dark inspector have their requested appearances applied.
|
|
40
|
+
- Verify the overview and inspector each show the actual sample value and are distinct views, not duplicates or caption-only variants. Verify the notification is present and the greeting and sample commands produce useful results.
|
|
41
|
+
- Treat terminal scenes as terminal results; do not substitute terminal output for feature UI or forge HTML. Do not invent routes or screens.
|
|
42
|
+
- Independently inspect every image and transcript for privacy and truthfulness, including the narrowly defined presentation mappings above. Unknown identities fail review.
|
|
43
|
+
- Confirm the plan against the actual capture tooling at capture time. Its TOML structure has been checked against the supplied field rules by inspection; no parser, plugin code, capture, or network call was run.
|
|
Binary file
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
{
|
|
2
|
+
"format": 1,
|
|
3
|
+
"plugin": "heinzel-example",
|
|
4
|
+
"core_version": "0.9.40",
|
|
5
|
+
"inputs_sha256": "855bf3b5a71afd5ca72803e6de2a0920cdb229a90cd1dd6297525b336f353f47",
|
|
6
|
+
"images": {
|
|
7
|
+
"docs/assets/screenshots/widget-and-status.png": "b9a98431c74dde61577a3c1061a3e1e0cf8c47cb7775d83b9685eaca515fd44a",
|
|
8
|
+
"docs/assets/screenshots/inspector.png": "0e1cd838c95633fe133ba2f4ed40ff8cb28b1a032bf451b33a41776ac5b07b61",
|
|
9
|
+
"docs/assets/screenshots/greeting-terminal.png": "d5d87d85f04dca0d2b4cab6ea7d01b0d321060826f76bb690ca08b48e7e56755",
|
|
10
|
+
"docs/assets/screenshots/plugin-notice.png": "9c5ed76532219e97d3e7780576487967609416804cd9becc61f8ac4805c762d3",
|
|
11
|
+
"docs/assets/screenshots/greeting-cli.png": "375b8962cc5c7c30ab9c63248ea2ac468f325afc3bc53932dd70c9c5da5478fd",
|
|
12
|
+
"docs/assets/screenshots/sample-json.png": "fcebdd36aba06edc9113cb2009094d20c07f83342ffec053e78d5e47d715e1f5"
|
|
13
|
+
},
|
|
14
|
+
"review_bundle": {
|
|
15
|
+
"format": 2,
|
|
16
|
+
"source_story": {
|
|
17
|
+
"path": "source-story.md",
|
|
18
|
+
"sha256": "e7a95d314a1d16b7830c57c69624425cbf3875d57e10260ec7416b5a941fcc70"
|
|
19
|
+
},
|
|
20
|
+
"definition": {
|
|
21
|
+
"format": 1,
|
|
22
|
+
"reviewer": "Codex feature-story agent",
|
|
23
|
+
"source_sha256": "50b56f504ae62164ad6841093f05abef327a6e4f5072af3d67ef62a31de2ea73",
|
|
24
|
+
"plan_sha256": "4349628e972b078196f4ce1aec8c7e248c5c3499a9c8b4b3ae42e4d6242660a7",
|
|
25
|
+
"story_sha256": "e7a95d314a1d16b7830c57c69624425cbf3875d57e10260ec7416b5a941fcc70"
|
|
26
|
+
},
|
|
27
|
+
"plugin": "heinzel-example",
|
|
28
|
+
"core_version": "0.9.40",
|
|
29
|
+
"inputs_sha256": "855bf3b5a71afd5ca72803e6de2a0920cdb229a90cd1dd6297525b336f353f47",
|
|
30
|
+
"screenshots": [
|
|
31
|
+
{
|
|
32
|
+
"path": "docs/assets/screenshots/widget-and-status.png",
|
|
33
|
+
"surface": "ui",
|
|
34
|
+
"caption": "Demo data: the constant 42 appears in both the Today widget and sidebar status."
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"path": "docs/assets/screenshots/inspector.png",
|
|
38
|
+
"surface": "ui",
|
|
39
|
+
"caption": "Demo data: open the plugin-owned inspector to see the same constant value, 42."
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"path": "docs/assets/screenshots/greeting-terminal.png",
|
|
43
|
+
"surface": "ui",
|
|
44
|
+
"caption": "Demo data: greet fictional Mira with structured JSON in the app's native terminal."
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"path": "docs/assets/screenshots/plugin-notice.png",
|
|
48
|
+
"surface": "ui",
|
|
49
|
+
"caption": "Demo data: a seeded Example is ready notice appears in the shared in-app notification panel."
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"path": "docs/assets/screenshots/greeting-cli.png",
|
|
53
|
+
"surface": "cli",
|
|
54
|
+
"caption": "Demo data: the typed hello operation greets fictional Mira from the CLI."
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"path": "docs/assets/screenshots/sample-json.png",
|
|
58
|
+
"surface": "cli",
|
|
59
|
+
"caption": "Demo data: sample returns 42 as JSON, the same constant used by the widget, status and inspector."
|
|
60
|
+
}
|
|
61
|
+
],
|
|
62
|
+
"images": {
|
|
63
|
+
"widget-and-status.png": "b9a98431c74dde61577a3c1061a3e1e0cf8c47cb7775d83b9685eaca515fd44a",
|
|
64
|
+
"inspector.png": "0e1cd838c95633fe133ba2f4ed40ff8cb28b1a032bf451b33a41776ac5b07b61",
|
|
65
|
+
"greeting-terminal.png": "d5d87d85f04dca0d2b4cab6ea7d01b0d321060826f76bb690ca08b48e7e56755",
|
|
66
|
+
"plugin-notice.png": "9c5ed76532219e97d3e7780576487967609416804cd9becc61f8ac4805c762d3",
|
|
67
|
+
"greeting-cli.png": "375b8962cc5c7c30ab9c63248ea2ac468f325afc3bc53932dd70c9c5da5478fd",
|
|
68
|
+
"sample-json.png": "fcebdd36aba06edc9113cb2009094d20c07f83342ffec053e78d5e47d715e1f5"
|
|
69
|
+
},
|
|
70
|
+
"transcripts": {
|
|
71
|
+
"widget-and-status.txt": "68df5b282b3ef97193bd8a156c3776d6ddad26956bc09119d7f5a99e1bcdfdae",
|
|
72
|
+
"inspector.txt": "59df51db803518a3aaeb0982f36e29d6d4dc67bb1d26737a77761fc5578b18b4",
|
|
73
|
+
"greeting-terminal.txt": "b0560cb65edafd7b11309430eb09f512c099f6c03e2b0df6d76b9edbf0a038b3",
|
|
74
|
+
"plugin-notice.txt": "753c9cb1e440b913a6ef237bd698a03d9cf17d442982d55b4b9aabb932aa7222",
|
|
75
|
+
"greeting-cli.txt": "0a315745bb1e963bf40b1ccfdc9a822532fa703f2c1b5013c8fe303b8cf0f59f",
|
|
76
|
+
"sample-json.txt": "084c799cd551dd1d8d5c5f9a5d593b2e931f5e36122ee5c793c1d08a19839cc0"
|
|
77
|
+
},
|
|
78
|
+
"bundle_sha256": "432a52c7a31ad73dc6a6a3feb3c96df4d8b343dc32a086e37c2c0746873df80d"
|
|
79
|
+
},
|
|
80
|
+
"privacy_review": {
|
|
81
|
+
"format": 1,
|
|
82
|
+
"bundle_sha256": "432a52c7a31ad73dc6a6a3feb3c96df4d8b343dc32a086e37c2c0746873df80d",
|
|
83
|
+
"reviewer": "Codex privacy agent",
|
|
84
|
+
"decision": "approve",
|
|
85
|
+
"checked_images": [
|
|
86
|
+
"widget-and-status.png",
|
|
87
|
+
"inspector.png",
|
|
88
|
+
"greeting-terminal.png",
|
|
89
|
+
"plugin-notice.png",
|
|
90
|
+
"greeting-cli.png",
|
|
91
|
+
"sample-json.png"
|
|
92
|
+
],
|
|
93
|
+
"checks": {
|
|
94
|
+
"tokens_absent": true,
|
|
95
|
+
"personal_data_absent": true,
|
|
96
|
+
"feature_relevant": true,
|
|
97
|
+
"multiple_ui_scenes": true,
|
|
98
|
+
"captions_accurate": true
|
|
99
|
+
},
|
|
100
|
+
"findings": []
|
|
101
|
+
}
|
|
102
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
text Hello, Mira!
|
|
Binary file
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
Skip to content
|
|
2
|
+
Heinzelmännchen
|
|
3
|
+
1
|
|
4
|
+
Heinzelmännchen
|
|
5
|
+
Contracts
|
|
6
|
+
Team graph
|
|
7
|
+
Organisation
|
|
8
|
+
Team roster
|
|
9
|
+
Example
|
|
10
|
+
Example: 42
|
|
11
|
+
M
|
|
12
|
+
Mira
|
|
13
|
+
· EM
|
|
14
|
+
Today
|
|
15
|
+
Today
|
|
16
|
+
Notifications
|
|
17
|
+
1 unread
|
|
18
|
+
Example is ready
|
|
19
|
+
18:31
|
|
20
|
+
All notifications
|
|
21
|
+
Example is ready
|
|
22
|
+
Open
|
|
23
|
+
Doctor: 4 checks need attention
|
|
24
|
+
|
|
25
|
+
ai.access ai access, system.doctor installation, system.prerequisite system.runner: claude…
|
|
26
|
+
|
|
27
|
+
Open
|
|
28
|
+
Example value
|
|
29
|
+
|
|
30
|
+
42
|
|
31
|
+
|
|
32
|
+
Ask about it
|
|
33
|
+
v0.9.40
|
|
34
|
+
Updates, off
|
|
35
|
+
0
|
|
36
|
+
System health, warning
|
|
37
|
+
?
|
|
38
|
+
Example: 42, off
|
|
39
|
+
Daemon not installed, off
|
|
40
|
+
Chat
|
|
41
|
+
Terminal
|
|
42
|
+
Demo complete
|
|
43
|
+
$ hz example hello --name Mira --json; printf '\033]0;Demo complete\007'
|
|
44
|
+
{
|
|
45
|
+
"text": "Hello, Mira!"
|
|
46
|
+
}
|
|
47
|
+
$
|
|
48
|
+
Audio
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width"><title>heinzel-example screenshots</title><style>body{font:16px/1.6 system-ui;margin:2rem;background:#faf8f3;color:#263b32}main{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,420px),1fr));gap:1rem}figure{margin:0;padding:1rem;background:white;border:1px solid #d8ddd3;border-radius:12px}img{width:100%;height:auto}figcaption{margin-top:.75rem}a:focus-visible{outline:3px solid #a64028}</style><h1>heinzel-example</h1><p>Isolated demonstration profile · Core 0.9.40 · Review these captures before committing. Click an image to inspect it at full size.</p><main><figure><a href="widget-and-status.png"><img src="widget-and-status.png" alt="Demo data: the constant 42 appears in both the Today widget and sidebar status."></a><figcaption>UI · Demo data: the constant 42 appears in both the Today widget and sidebar status.</figcaption></figure><figure><a href="inspector.png"><img src="inspector.png" alt="Demo data: open the plugin-owned inspector to see the same constant value, 42."></a><figcaption>UI · Demo data: open the plugin-owned inspector to see the same constant value, 42.</figcaption></figure><figure><a href="greeting-terminal.png"><img src="greeting-terminal.png" alt="Demo data: greet fictional Mira with structured JSON in the app's native terminal."></a><figcaption>UI · Demo data: greet fictional Mira with structured JSON in the app's native terminal.</figcaption></figure><figure><a href="plugin-notice.png"><img src="plugin-notice.png" alt="Demo data: a seeded Example is ready notice appears in the shared in-app notification panel."></a><figcaption>UI · Demo data: a seeded Example is ready notice appears in the shared in-app notification panel.</figcaption></figure><figure><a href="greeting-cli.png"><img src="greeting-cli.png" alt="Demo data: the typed hello operation greets fictional Mira from the CLI."></a><figcaption>CLI · Demo data: the typed hello operation greets fictional Mira from the CLI.</figcaption></figure><figure><a href="sample-json.png"><img src="sample-json.png" alt="Demo data: sample returns 42 as JSON, the same constant used by the widget, status and inspector."></a><figcaption>CLI · Demo data: sample returns 42 as JSON, the same constant used by the widget, status and inspector.</figcaption></figure></main></html>
|
|
Binary file
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
Skip to content
|
|
2
|
+
Heinzelmännchen
|
|
3
|
+
1
|
|
4
|
+
Heinzelmännchen
|
|
5
|
+
Contracts
|
|
6
|
+
Team graph
|
|
7
|
+
Organisation
|
|
8
|
+
Team roster
|
|
9
|
+
Example
|
|
10
|
+
Example: 42
|
|
11
|
+
M
|
|
12
|
+
Mira
|
|
13
|
+
· EM
|
|
14
|
+
Today
|
|
15
|
+
Today
|
|
16
|
+
Notifications
|
|
17
|
+
1 unread
|
|
18
|
+
Example is ready
|
|
19
|
+
18:31
|
|
20
|
+
All notifications
|
|
21
|
+
Example is ready
|
|
22
|
+
Open
|
|
23
|
+
Example value
|
|
24
|
+
|
|
25
|
+
42
|
|
26
|
+
|
|
27
|
+
Ask about it
|
|
28
|
+
v0.9.40
|
|
29
|
+
Updates, off
|
|
30
|
+
0
|
|
31
|
+
System health, warning
|
|
32
|
+
?
|
|
33
|
+
Example: 42, off
|
|
34
|
+
Daemon not installed, off
|
|
35
|
+
Chat
|
|
36
|
+
Example
|
|
37
|
+
Example
|
|
38
|
+
|
|
39
|
+
42
|
|
40
|
+
|
|
41
|
+
Audio
|
|
Binary file
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
Skip to content
|
|
2
|
+
Heinzelmännchen
|
|
3
|
+
1
|
|
4
|
+
Heinzelmännchen
|
|
5
|
+
Contracts
|
|
6
|
+
Team graph
|
|
7
|
+
Organisation
|
|
8
|
+
Team roster
|
|
9
|
+
Example
|
|
10
|
+
Example: 42
|
|
11
|
+
M
|
|
12
|
+
Mira
|
|
13
|
+
· EM
|
|
14
|
+
Today
|
|
15
|
+
Today
|
|
16
|
+
Notifications
|
|
17
|
+
1 unread
|
|
18
|
+
Example is ready
|
|
19
|
+
18:31
|
|
20
|
+
All notifications
|
|
21
|
+
Example is ready
|
|
22
|
+
Open
|
|
23
|
+
Example value
|
|
24
|
+
|
|
25
|
+
42
|
|
26
|
+
|
|
27
|
+
Ask about it
|
|
28
|
+
v0.9.40
|
|
29
|
+
Updates, off
|
|
30
|
+
0
|
|
31
|
+
System health, warning
|
|
32
|
+
?
|
|
33
|
+
Example: 42, off
|
|
34
|
+
Daemon not installed, off
|
|
35
|
+
Chat
|
|
36
|
+
New chat
|
|
37
|
+
Ask about your setup, your team's contracts or what to do next. The chat reads with hz and asks you before it changes anything.
|
|
38
|
+
Your message
|
|
39
|
+
Default
|
|
40
|
+
Audio
|
|
41
|
+
Notifications
|
|
42
|
+
All
|
|
43
|
+
Drafts
|
|
44
|
+
Failed runs
|
|
45
|
+
Health
|
|
46
|
+
Releases
|
|
47
|
+
Plugins
|
|
48
|
+
Tests
|
|
49
|
+
Heinzel check-ins
|
|
50
|
+
Calendar
|
|
51
|
+
Today
|
|
52
|
+
Example is ready
|
|
53
|
+
18:31
|
|
54
|
+
quiet mode is on: hz system config set system.notify.quiet false
|
|
55
|
+
Unread
|
|
56
|
+
desktop notifications through Heinzel Notifier; a click opens the screen
|
|
57
|
+
Send a test notification
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
42
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
## Audience
|
|
2
|
+
|
|
3
|
+
Plugin authors evaluating a small, working reference for Heinzelmännchen extensions.
|
|
4
|
+
|
|
5
|
+
## Outcome
|
|
6
|
+
|
|
7
|
+
See one value move from an operation into the Today widget, sidebar status, and an inspector pane; then see a typed greeting and a seeded notification. The examples show integration points to explore, not a production business workflow.
|
|
8
|
+
|
|
9
|
+
## Scenes
|
|
10
|
+
|
|
11
|
+
1. **Widget and status, light:** The Today widget and sidebar both show the sample value, 42. `src/heinzel_example/__init__.py` declares `sample`, `@module.widget(source="sample")`, and `@module.status(source="sample", slots={"footer": True, "sidebar": True})`.
|
|
12
|
+
2. **Inspector, dark:** The real Example pane displays 42. `module.nav`, `module.action`, and the status effect navigate to `/?panel=example:inspector`; `module.view(..., name="inspector", source="sample")` owns that pane, rendered by `src/heinzel_example/views/index.js`.
|
|
13
|
+
3. **Greeting in the app terminal:** Run the fictional Mira greeting with JSON output. This is a native terminal result, not a feature UI. `src/heinzel_example/hello/__init__.py` declares the collapsed `hello` operation; `_service.py` constructs the greeting.
|
|
14
|
+
4. **Notification:** Open the shared notification panel to see the seeded “Example is ready” notice. The `notify` operation in `src/heinzel_example/__init__.py` emits it; `docs/screenshot_fixture.py` seeds it in the isolated capture profile.
|
|
15
|
+
5. **Greeting CLI:** Show the same fictional greeting as a direct CLI result.
|
|
16
|
+
6. **Sample JSON CLI:** Show the source value as structured output, connecting the CLI to the widget and inspector.
|
|
17
|
+
|
|
18
|
+
## Fictional fixtures and presentation
|
|
19
|
+
|
|
20
|
+
Use the existing `docs/screenshot_fixture.py` bootstrap and its isolated profile; do not create fixture files. Mira is fictional, and 42 is the actual constant returned by `sample`. The notice is seeded demonstration data. Captions identify demo data.
|
|
21
|
+
|
|
22
|
+
Normal presentation fictionalization is explicitly limited to verified owning-interpreter paths becoming `/demo-profile/.venv`, and only the verified whole hostname detail in the genuine Doctor row becoming `demo-host`. These mappings change no SDK health status or remaining detail and establish no privacy acceptance. Unknown identities still fail, and independent review must inspect every image and transcript.
|
|
23
|
+
|
|
24
|
+
## Privacy pitfalls
|
|
25
|
+
|
|
26
|
+
The bootstrap disables native, Doctor, and release notifications and invokes the plugin notice in an isolated profile; it does not by itself prove that captures contain no personal information. Inspect paths, hostnames, account names, notifications, timestamps, terminal output, and other incidental content. Do not conceal unknown identities with assumed substitutions.
|
|
27
|
+
|
|
28
|
+
## Source-bound UI surface inventory
|
|
29
|
+
|
|
30
|
+
- **Plugin entrypoint:** `pyproject.toml` declares `heinzel.modules` entry `example = "heinzel_example"`. `src/heinzel_example/__init__.py` declares the root `Module("example", ...)`; `src/heinzel_example/hello/__init__.py` declares the discovered `Module("hello", ...)` submodule.
|
|
31
|
+
- **Genuine feature UI:** The Core-rendered Today metric and footer/sidebar status come from the widget and status declarations. The plugin-owned inspector is a real view at the declared panel target, implemented in `src/heinzel_example/views/index.js`. Its loading state and value are rendered using SDK React; it declares no action row. The same actual value across these surfaces is intentional, but the overview and inspector must remain visually and functionally distinct captures.
|
|
32
|
+
- **Other Core-rendered contributions:** `module.action` and `module.nav` open the inspector. `notify` contributes a plugin notice to the shared notification UI. `module.settings(ExampleSettings)` registers the `greeting` setting in `src/heinzel_example/_models.py`; `@module.info` contributes details to system info. The non-read-only `notify` operation declares an ordinary confirmation. These declarations can give rise to generic Core surfaces, but their precise layouts are not supplied here and must not be invented. No channel or setup contribution is declared in the supplied entrypoints.
|
|
33
|
+
- **Operations and terminal:** Root operations are `info`, `sample`, and `notify`; the hello submodule declares `hello`. CLI output is genuine terminal output, including when displayed in the app terminal, and is not evidence of a feature UI. `README.md` documents `hz example hello`, `hz example info`, JSON output, and system info; the source also declares `sample` and `notify`.
|
|
34
|
+
- **External provider UI:** None is declared in the supplied plugin source. No external provider screen is needed for this story.
|
|
35
|
+
- **Unresolved evidence:** `README.md` describes a health check, but the supplied module declarations contain no explicit health-check contribution; do not invent one. The README also references `tests/contributions_test.py`, which is not among the supplied files. Core implementation and the screenshot author guide are not supplied, so generic surface details and capture behavior require observation during explicit capture. The existing plan is preserved because it already covers two real feature UI scenes, a notice, and useful CLI results.
|
|
36
|
+
|
|
37
|
+
## Acceptance criteria
|
|
38
|
+
|
|
39
|
+
- Capture all six planned scenes from the real app or CLI with the existing bootstrap, and confirm the light overview and dark inspector have their requested appearances applied.
|
|
40
|
+
- Verify the overview and inspector each show the actual sample value and are distinct views, not duplicates or caption-only variants. Verify the notification is present and the greeting and sample commands produce useful results.
|
|
41
|
+
- Treat terminal scenes as terminal results; do not substitute terminal output for feature UI or forge HTML. Do not invent routes or screens.
|
|
42
|
+
- Independently inspect every image and transcript for privacy and truthfulness, including the narrowly defined presentation mappings above. Unknown identities fail review.
|
|
43
|
+
- Confirm the plan against the actual capture tooling at capture time. Its TOML structure has been checked against the supplied field rules by inspection; no parser, plugin code, capture, or network call was run.
|
|
Binary file
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
Skip to content
|
|
2
|
+
Heinzelmännchen
|
|
3
|
+
1
|
|
4
|
+
Heinzelmännchen
|
|
5
|
+
Contracts
|
|
6
|
+
Team graph
|
|
7
|
+
Organisation
|
|
8
|
+
Team roster
|
|
9
|
+
Example
|
|
10
|
+
Example: 42
|
|
11
|
+
M
|
|
12
|
+
Mira
|
|
13
|
+
· EM
|
|
14
|
+
Today
|
|
15
|
+
Today
|
|
16
|
+
Notifications
|
|
17
|
+
1 unread
|
|
18
|
+
Example is ready
|
|
19
|
+
18:31
|
|
20
|
+
All notifications
|
|
21
|
+
Example is ready
|
|
22
|
+
Open
|
|
23
|
+
Example value
|
|
24
|
+
|
|
25
|
+
42
|
|
26
|
+
|
|
27
|
+
Ask about it
|
|
28
|
+
v0.9.40
|
|
29
|
+
Updates, off
|
|
30
|
+
0
|
|
31
|
+
System health, warning
|
|
32
|
+
?
|
|
33
|
+
Example: 42, off
|
|
34
|
+
Daemon not installed, off
|
|
35
|
+
Chat
|
|
36
|
+
New chat
|
|
37
|
+
Ask about your setup, your team's contracts or what to do next. The chat reads with hz and asks you before it changes anything.
|
|
38
|
+
Your message
|
|
39
|
+
Default
|
|
40
|
+
Audio
|
|
Binary file
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"format": 1,
|
|
3
|
+
"reviewer": "Codex feature-story agent",
|
|
4
|
+
"source_sha256": "50b56f504ae62164ad6841093f05abef327a6e4f5072af3d67ef62a31de2ea73",
|
|
5
|
+
"plan_sha256": "4349628e972b078196f4ce1aec8c7e248c5c3499a9c8b4b3ae42e4d6242660a7",
|
|
6
|
+
"story_sha256": "e7a95d314a1d16b7830c57c69624425cbf3875d57e10260ec7416b5a941fcc70"
|
|
7
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Seed only the example's own notice in an isolated, in-app-only demonstration profile."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import sys
|
|
5
|
+
|
|
6
|
+
from heinzel import Config, Kernel, Notifications, Settings
|
|
7
|
+
from heinzel.heads.cli import build
|
|
8
|
+
from heinzel.kernel import discover
|
|
9
|
+
from heinzel_example import notify
|
|
10
|
+
|
|
11
|
+
os.environ.update(
|
|
12
|
+
HZ_SYSTEM_NOTIFY__NATIVE="false",
|
|
13
|
+
HZ_SYSTEM_NOTIFY__DOCTOR="false",
|
|
14
|
+
HZ_SYSTEM_NOTIFY__RELEASE="false",
|
|
15
|
+
HZ_SYSTEM_NOTIFY__QUIET="true",
|
|
16
|
+
HZ_SYSTEM_NOTIFY__WORKING_HOURS="false",
|
|
17
|
+
)
|
|
18
|
+
config = Config.load()
|
|
19
|
+
records, errors = discover()
|
|
20
|
+
kernel = Kernel(config.settings(Settings, "hz"), records, errors, config)
|
|
21
|
+
notify(kernel.resolve(Notifications))
|
|
22
|
+
sys.argv = ["hz", *sys.argv[1:]]
|
|
23
|
+
build(kernel)()
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
format = 1
|
|
2
|
+
bootstrap = "docs/screenshot_fixture.py"
|
|
3
|
+
|
|
4
|
+
[[scenes]]
|
|
5
|
+
name = "widget-and-status"
|
|
6
|
+
surface = "ui"
|
|
7
|
+
route = "/"
|
|
8
|
+
appearance = "light"
|
|
9
|
+
caption = "Demo data: the constant 42 appears in both the Today widget and sidebar status."
|
|
10
|
+
|
|
11
|
+
[[scenes.steps]]
|
|
12
|
+
action = "wait"
|
|
13
|
+
text = "Example value"
|
|
14
|
+
|
|
15
|
+
[[scenes.steps]]
|
|
16
|
+
action = "wait"
|
|
17
|
+
text = "Example: 42"
|
|
18
|
+
|
|
19
|
+
[[scenes.steps]]
|
|
20
|
+
action = "click"
|
|
21
|
+
role = "button"
|
|
22
|
+
name_regex = "^Dismiss Doctor"
|
|
23
|
+
optional = true
|
|
24
|
+
|
|
25
|
+
[[scenes]]
|
|
26
|
+
name = "inspector"
|
|
27
|
+
surface = "ui"
|
|
28
|
+
route = "/?panel=example:inspector"
|
|
29
|
+
appearance = "dark"
|
|
30
|
+
caption = "Demo data: open the plugin-owned inspector to see the same constant value, 42."
|
|
31
|
+
|
|
32
|
+
[[scenes.steps]]
|
|
33
|
+
action = "wait"
|
|
34
|
+
role = "region"
|
|
35
|
+
name = "Example"
|
|
36
|
+
|
|
37
|
+
[[scenes.steps]]
|
|
38
|
+
action = "wait"
|
|
39
|
+
text = "42"
|
|
40
|
+
|
|
41
|
+
[[scenes.steps]]
|
|
42
|
+
action = "click"
|
|
43
|
+
role = "button"
|
|
44
|
+
name_regex = "^Dismiss Doctor"
|
|
45
|
+
optional = true
|
|
46
|
+
|
|
47
|
+
[[scenes]]
|
|
48
|
+
name = "greeting-terminal"
|
|
49
|
+
surface = "ui"
|
|
50
|
+
route = "/"
|
|
51
|
+
caption = "Demo data: greet fictional Mira with structured JSON in the app's native terminal."
|
|
52
|
+
|
|
53
|
+
[[scenes.steps]]
|
|
54
|
+
action = "terminal"
|
|
55
|
+
command = ["example", "hello", "--name", "Mira", "--json"]
|
|
56
|
+
|
|
57
|
+
[[scenes]]
|
|
58
|
+
name = "plugin-notice"
|
|
59
|
+
surface = "ui"
|
|
60
|
+
route = "/"
|
|
61
|
+
caption = "Demo data: a seeded Example is ready notice appears in the shared in-app notification panel."
|
|
62
|
+
|
|
63
|
+
[[scenes.steps]]
|
|
64
|
+
action = "wait"
|
|
65
|
+
text = "Example value"
|
|
66
|
+
|
|
67
|
+
[[scenes.steps]]
|
|
68
|
+
action = "click"
|
|
69
|
+
role = "button"
|
|
70
|
+
name_regex = "^Dismiss Doctor"
|
|
71
|
+
optional = true
|
|
72
|
+
|
|
73
|
+
[[scenes.steps]]
|
|
74
|
+
action = "click"
|
|
75
|
+
role = "button"
|
|
76
|
+
name_regex = "^Notifications"
|
|
77
|
+
|
|
78
|
+
[[scenes.steps]]
|
|
79
|
+
action = "wait"
|
|
80
|
+
text = "Example is ready"
|
|
81
|
+
|
|
82
|
+
[scenes.viewport]
|
|
83
|
+
width = 1280
|
|
84
|
+
height = 650
|
|
85
|
+
|
|
86
|
+
[[scenes]]
|
|
87
|
+
name = "greeting-cli"
|
|
88
|
+
surface = "cli"
|
|
89
|
+
caption = "Demo data: the typed hello operation greets fictional Mira from the CLI."
|
|
90
|
+
command = ["example", "hello", "--name", "Mira"]
|
|
91
|
+
|
|
92
|
+
[[scenes]]
|
|
93
|
+
name = "sample-json"
|
|
94
|
+
surface = "cli"
|
|
95
|
+
caption = "Demo data: sample returns 42 as JSON, the same constant used by the widget, status and inspector."
|
|
96
|
+
command = ["example", "sample", "--json"]
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"ruff==0.17.2"
|
|
15
15
|
],
|
|
16
16
|
"core": {
|
|
17
|
-
"version": "0.9.
|
|
17
|
+
"version": "0.9.40",
|
|
18
18
|
"dependencies": [
|
|
19
19
|
"croniter>=6.2.4",
|
|
20
20
|
"fastapi>=0.161",
|
|
@@ -29,10 +29,12 @@
|
|
|
29
29
|
"pydantic-ai-slim[openai]==2.61.0; extra == \"openai\"",
|
|
30
30
|
"pydantic-settings<3,>=2.11.0",
|
|
31
31
|
"pydantic<3,>=2.12.0",
|
|
32
|
+
"pyjwt[crypto]<3,>=2.15.1; extra == \"openai\"",
|
|
32
33
|
"pyyaml<7,>=6.0.2",
|
|
33
34
|
"rich>=14.2.0",
|
|
34
35
|
"tomlkit>=0.13",
|
|
35
36
|
"typer>=0.23.0",
|
|
37
|
+
"uv==0.13.7",
|
|
36
38
|
"uvicorn>=0.54",
|
|
37
39
|
"wsproto>=1.3"
|
|
38
40
|
]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "heinzel-example"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.5.2"
|
|
4
4
|
description = "Show how a Heinzelmännchen plugin is built."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [{ name = "Helmut Hoffer von Ankershoffen", email = "helmuthva@gmail.com" }]
|
|
@@ -141,3 +141,42 @@ pythonVersion = "3.12"
|
|
|
141
141
|
|
|
142
142
|
[tool.hatch.build.targets.sdist]
|
|
143
143
|
exclude = [".venv", ".acceptance", ".preview", "dist", "web/node_modules", "**/__pycache__", ".pytest_cache", ".mypy_cache", ".coverage*"]
|
|
144
|
+
|
|
145
|
+
[tool.heinzel.catalog]
|
|
146
|
+
title = "Example Plugin"
|
|
147
|
+
category = "reference"
|
|
148
|
+
highlights = [
|
|
149
|
+
"A working reference for extension authors",
|
|
150
|
+
"Operations, settings and head contributions",
|
|
151
|
+
"Source to explore alongside the scaffold guide",
|
|
152
|
+
]
|
|
153
|
+
|
|
154
|
+
[[tool.heinzel.catalog.screenshots]]
|
|
155
|
+
path = "docs/assets/screenshots/widget-and-status.png"
|
|
156
|
+
surface = "ui"
|
|
157
|
+
caption = "Demo data: the constant 42 appears in both the Today widget and sidebar status."
|
|
158
|
+
|
|
159
|
+
[[tool.heinzel.catalog.screenshots]]
|
|
160
|
+
path = "docs/assets/screenshots/inspector.png"
|
|
161
|
+
surface = "ui"
|
|
162
|
+
caption = "Demo data: open the plugin-owned inspector to see the same constant value, 42."
|
|
163
|
+
|
|
164
|
+
[[tool.heinzel.catalog.screenshots]]
|
|
165
|
+
path = "docs/assets/screenshots/greeting-terminal.png"
|
|
166
|
+
surface = "ui"
|
|
167
|
+
caption = "Demo data: greet fictional Mira with structured JSON in the app's native terminal."
|
|
168
|
+
|
|
169
|
+
[[tool.heinzel.catalog.screenshots]]
|
|
170
|
+
path = "docs/assets/screenshots/plugin-notice.png"
|
|
171
|
+
surface = "ui"
|
|
172
|
+
caption = "Demo data: a seeded Example is ready notice appears in the shared in-app notification panel."
|
|
173
|
+
|
|
174
|
+
[[tool.heinzel.catalog.screenshots]]
|
|
175
|
+
path = "docs/assets/screenshots/greeting-cli.png"
|
|
176
|
+
surface = "cli"
|
|
177
|
+
caption = "Demo data: the typed hello operation greets fictional Mira from the CLI."
|
|
178
|
+
|
|
179
|
+
[[tool.heinzel.catalog.screenshots]]
|
|
180
|
+
path = "docs/assets/screenshots/sample-json.png"
|
|
181
|
+
surface = "cli"
|
|
182
|
+
caption = "Demo data: sample returns 42 as JSON, the same constant used by the widget, status and inspector."
|
|
@@ -640,9 +640,9 @@ nodejs-wheel-binaries==24.19.0 \
|
|
|
640
640
|
--hash=sha256:d9074c665ea68b04e183d82482c86dc907d3a9bd15eb6cf85542cb785266bb36 \
|
|
641
641
|
--hash=sha256:db217eef8cab8551667863379b08db4d9067403f6cbbe87481eb40edceb8aa9b \
|
|
642
642
|
--hash=sha256:e12cbfd69089504e42fb14194ce734a9dcf3eb38c820ca63dd511d36fb964e9c
|
|
643
|
-
opentelemetry-api==1.45.
|
|
644
|
-
--hash=sha256:
|
|
645
|
-
--hash=sha256:
|
|
643
|
+
opentelemetry-api==1.45.2 \
|
|
644
|
+
--hash=sha256:2cbd737377e710ee740d261c94e93fa0f08e6d037c18f17513cc0a2d94479a34 \
|
|
645
|
+
--hash=sha256:d7b0008e21e5fd61cbe7a7f34ca3b6905a78ab677d9bc395e299359c75cda6b4
|
|
646
646
|
packaging==26.3 \
|
|
647
647
|
--hash=sha256:94edc256424af38762eb31306eed28beb9f0efc50a8837492c9d6fd6004aed79 \
|
|
648
648
|
--hash=sha256:d7193f7c8e4e93f444fde0262bf90af30e16fa0ad0ad44cb553c87339b23cd1c
|
|
@@ -1146,6 +1146,26 @@ typing-inspection==0.4.4 \
|
|
|
1146
1146
|
tzdata==2026.6 \
|
|
1147
1147
|
--hash=sha256:0a10eec6e13ef16b627fabed9a5f2ba61a62b1c67f327305f4e7e412a70b4aec \
|
|
1148
1148
|
--hash=sha256:85d2cd9c09f81f0bb29db27759fc83af4f1e620efb814f8c5bf8b4cc4feece6d
|
|
1149
|
+
uv==0.13.7 \
|
|
1150
|
+
--hash=sha256:08f16fd463926786b702b497473511deae4b3e17a2fa6d22180950d6059a120d \
|
|
1151
|
+
--hash=sha256:158953b8669bee6f4bc2babdd997e34ff9f0d57170093cfe907f64448292b7c3 \
|
|
1152
|
+
--hash=sha256:1bc8543d930464bbb22ac01bb1a660a448235e558014914de1e1cd5b993361b8 \
|
|
1153
|
+
--hash=sha256:2835e2ab397d0db86323b9975dce75ecd76aa9cfa0d6a2aea84734aae7f8c9b3 \
|
|
1154
|
+
--hash=sha256:2c9bdc4a872b60a93c5f26c0791089ea11585a4f9d3b3c017d78eb8487505e25 \
|
|
1155
|
+
--hash=sha256:55e741a380a98008fc4985cf069855f36bc50242ef438e21a466786f5bc84da8 \
|
|
1156
|
+
--hash=sha256:57ff66891d9a738ec087c23fdde842ac8e5eb63189ffed6ee95caee1b82ceb54 \
|
|
1157
|
+
--hash=sha256:5e766791cb825d7a07e2ef9e622d307b48754fb682a31ba7bc5f272fab9ea395 \
|
|
1158
|
+
--hash=sha256:5f37cc4d4660e4aee8a24d0dc179a0b0ce99506259c6796d37fa69bca9543a03 \
|
|
1159
|
+
--hash=sha256:89df450624dec8c48b8b5a7adb654928cc50e95753f869c70cd65ef8333f2197 \
|
|
1160
|
+
--hash=sha256:8b8ac028ae4ebb2a3f9d04907c61794f2cf8d7a7002bfbb4019a3dee28351fb2 \
|
|
1161
|
+
--hash=sha256:8fc6019740794df995085f7b278d99dc11ccacffad9c63957278d3a6e272280b \
|
|
1162
|
+
--hash=sha256:917733990ebc178318af0321d6873823ed5da707e1c4b1e5060ac2065a81f1f3 \
|
|
1163
|
+
--hash=sha256:94f65a8ac5826dff76a93cb3cafbaad15def1788c63da2ce5ce09e0bd1303e7a \
|
|
1164
|
+
--hash=sha256:952dcae9b1a7742f2fab28e82391fbfabe8807e4e9363f674b0f6be1053b8dd4 \
|
|
1165
|
+
--hash=sha256:a90f5d95716ab83091f0f73a8e7ec64e557abf2a28537fcd719b2ac88e6f725a \
|
|
1166
|
+
--hash=sha256:d30cafb7070901ba35353ec64cf228ae46caf79ac0f6fae329f95468b1482531 \
|
|
1167
|
+
--hash=sha256:f91a229093163eefca89ea1b220a221d64c3beade05d03519a6584d1797a5a5f \
|
|
1168
|
+
--hash=sha256:fd04bf01ba5f2829f4f94ca8f0c24a743f21e73d75045613ed6fc2fd66fc7bda
|
|
1149
1169
|
uvicorn==0.54.0 \
|
|
1150
1170
|
--hash=sha256:505bdb0f318731d45f1f712071fc781a8981f6847a31c902c9f5e652d4f67faf \
|
|
1151
1171
|
--hash=sha256:a2e33cbfaa0306f8e6b0c13e0cb89d7d7a2da3e62b90c66e18c33d9807b28620
|
|
@@ -6,7 +6,7 @@ below it that declares `module = Module(...)` becomes a submodule (see `hello/`)
|
|
|
6
6
|
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
|
|
9
|
-
from heinzel import MetricWidget, Module, Navigate, NoticeKind, Notifications, StatusItem
|
|
9
|
+
from heinzel import DetailLine, MetricWidget, Module, Navigate, NoticeKind, Notifications, StatusItem
|
|
10
10
|
|
|
11
11
|
from heinzel_example._models import ExampleAbout, ExampleSettings
|
|
12
12
|
from heinzel_example._service import ExampleService
|
|
@@ -46,10 +46,15 @@ def notify(notifications: Notifications) -> str:
|
|
|
46
46
|
return notice.title if notice else "Notifications are disabled"
|
|
47
47
|
|
|
48
48
|
|
|
49
|
-
@module.status(source="sample", order=700, slots={"footer":
|
|
49
|
+
@module.status(source="sample", order=700, slots={"footer": True, "sidebar": True})
|
|
50
50
|
def status(value: int) -> StatusItem:
|
|
51
|
-
"""
|
|
52
|
-
return StatusItem(
|
|
51
|
+
"""Contribute the footer icon and the sidebar item; a click opens the Example pane (the view below)."""
|
|
52
|
+
return StatusItem(
|
|
53
|
+
text=f"Example: {value}",
|
|
54
|
+
icon="star",
|
|
55
|
+
detail=[DetailLine(text="Example")],
|
|
56
|
+
effect=Navigate(path="/?panel=example:inspector"),
|
|
57
|
+
)
|
|
53
58
|
|
|
54
59
|
|
|
55
60
|
@module.widget(source="sample", order=700)
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// This small view needs no bundler. A specialist view can use the same versioned SDK with its own build.
|
|
2
|
+
// Pane structure: the content only. It has no actions, so there is no divider and no bottom action row.
|
|
2
3
|
export default function createView(sdk) {
|
|
3
4
|
if (sdk.abi !== 1) throw new Error("Example requires plugin SDK 1");
|
|
4
|
-
return function Inspector({data, loading
|
|
5
|
+
return function Inspector({data, loading}) {
|
|
5
6
|
return sdk.React.createElement("section", {"aria-label": "Example", className: "p-4"},
|
|
6
7
|
sdk.React.createElement("h2", null, "Example"),
|
|
7
|
-
sdk.React.createElement("p", {role: "status"}, loading ? "Loading…" :
|
|
8
|
-
sdk.React.createElement(sdk.Button, {onClick: onClose}, "Close example"));
|
|
8
|
+
sdk.React.createElement("p", {role: "status", className: "text-6xl font-semibold"}, loading ? "Loading…" : String(data)));
|
|
9
9
|
};
|
|
10
10
|
}
|
|
@@ -4,7 +4,7 @@ from types import SimpleNamespace
|
|
|
4
4
|
from unittest.mock import Mock
|
|
5
5
|
|
|
6
6
|
import pytest
|
|
7
|
-
from heinzel import NoticeKind, Notifications, ViewLet
|
|
7
|
+
from heinzel import NoticeKind, Notifications, StatusLet, ViewLet
|
|
8
8
|
|
|
9
9
|
from heinzel_example import module, notify, sample, status, today
|
|
10
10
|
|
|
@@ -20,6 +20,18 @@ def test_example_value_owns_its_status_and_today_widget():
|
|
|
20
20
|
assert view.source == "sample"
|
|
21
21
|
|
|
22
22
|
|
|
23
|
+
def test_footer_icon_opens_the_example_pane_with_the_value():
|
|
24
|
+
item = status(sample())
|
|
25
|
+
[let] = [let for let in module.lets if isinstance(let, StatusLet)]
|
|
26
|
+
assert dict(let.slots) == {"footer": True, "sidebar": True}
|
|
27
|
+
assert item.icon == "star"
|
|
28
|
+
assert item.detail[0].text == "Example"
|
|
29
|
+
assert item.effect.path == "/?panel=example:inspector"
|
|
30
|
+
[view] = [let for let in module.lets if isinstance(let, ViewLet)]
|
|
31
|
+
assert view.title == "Example"
|
|
32
|
+
assert view.source == "sample"
|
|
33
|
+
|
|
34
|
+
|
|
23
35
|
@pytest.mark.parametrize("enabled", [True, False])
|
|
24
36
|
def test_plugin_notice_uses_the_shared_notification_policy(enabled):
|
|
25
37
|
notifications = Mock(spec=Notifications)
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
## 0.4.0
|
|
4
|
-
|
|
5
|
-
Move this plugin to its independent repository project for the Heinzel 0.9 plugin contract.
|
|
6
|
-
Own its dependencies, tests and artifacts; consume public contracts without concrete provider dependencies.
|
|
7
|
-
|
|
8
|
-
Earlier history is preserved in the source repository named in README.md.
|
heinzel_example-0.4.0/PKG-INFO
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.5
|
|
2
|
-
Name: heinzel-example
|
|
3
|
-
Version: 0.4.0
|
|
4
|
-
Summary: Show how a Heinzelmännchen plugin is built.
|
|
5
|
-
Project-URL: Source, https://github.com/helmut-hoffer-von-ankershoffen/heinzel-plugins/tree/main/plugins/heinzel-example
|
|
6
|
-
Project-URL: Changelog, https://github.com/helmut-hoffer-von-ankershoffen/heinzel-plugins/blob/main/plugins/heinzel-example/CHANGELOG.md
|
|
7
|
-
Project-URL: Issues, https://github.com/helmut-hoffer-von-ankershoffen/heinzel-plugins/issues
|
|
8
|
-
Author-email: Helmut Hoffer von Ankershoffen <helmuthva@gmail.com>
|
|
9
|
-
License-Expression: MIT
|
|
10
|
-
License-File: LICENSE
|
|
11
|
-
Keywords: heinzel,heinzel-plugin,heinzelmaennchen
|
|
12
|
-
Classifier: Development Status :: 3 - Alpha
|
|
13
|
-
Classifier: Environment :: Console
|
|
14
|
-
Classifier: Operating System :: MacOS
|
|
15
|
-
Classifier: Operating System :: POSIX :: Linux
|
|
16
|
-
Classifier: Programming Language :: Python :: 3
|
|
17
|
-
Classifier: Typing :: Typed
|
|
18
|
-
Requires-Python: >=3.12
|
|
19
|
-
Requires-Dist: heinzel<0.10,>=0.9.1
|
|
20
|
-
Description-Content-Type: text/markdown
|
|
21
|
-
|
|
22
|
-
# heinzel-example
|
|
23
|
-
|
|
24
|
-
Show how a Heinzelmännchen plugin is built: one module with an operation, settings, a health check and a submodule.
|
|
25
|
-
|
|
26
|
-
A plugin for [Heinzelmännchen](https://github.com/helmut-hoffer-von-ankershoffen/heinzel), the open-source, AI-driven
|
|
27
|
-
operating system for product development teams. It lives in
|
|
28
|
-
[heinzel-plugins](https://github.com/helmut-hoffer-von-ankershoffen/heinzel-plugins). Its earlier history is preserved
|
|
29
|
-
in heinzel-contrib and the archived heinzel-example repository.
|
|
30
|
-
|
|
31
|
-
## Install
|
|
32
|
-
|
|
33
|
-
With Heinzelmännchen installed (`uv tool install git+https://github.com/helmut-hoffer-von-ankershoffen/heinzel`):
|
|
34
|
-
|
|
35
|
-
```bash
|
|
36
|
-
hz system plugin add "heinzel-example @ git+https://github.com/helmut-hoffer-von-ankershoffen/heinzel-plugins#subdirectory=plugins/heinzel-example"
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
Running `hz system plugin add` again upgrades; `hz system plugin remove heinzel-example` removes it.
|
|
40
|
-
|
|
41
|
-
## Use
|
|
42
|
-
|
|
43
|
-
```bash
|
|
44
|
-
hz example info # this plugin, its version and the Heinzelmännchen it runs on
|
|
45
|
-
hz example hello --name Ada # a submodule collapsed into a command
|
|
46
|
-
hz example info --json # every command speaks JSON, for scripts and agents
|
|
47
|
-
hz system info # includes a section contributed by this plugin
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
## Develop
|
|
51
|
-
|
|
52
|
-
From the repository root: `make check-fast NAME=example` runs this plugin's edit loop; `make check NAME=example`
|
|
53
|
-
runs its full checks. `make build NAME=example` and `make acceptance NAME=example` verify its installed artifact.
|
|
54
|
-
The modules live in
|
|
55
|
-
`src/heinzel_example/`; read the root [AGENTS.md](../../AGENTS.md) before changing them.
|
|
56
|
-
|
|
57
|
-
Development and release commands: [repository guide](../../README.md).
|
|
58
|
-
|
|
59
|
-
Migration provenance: heinzel-contrib, before the 0.9 plugin-boundary migration.
|
heinzel_example-0.4.0/README.md
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
# heinzel-example
|
|
2
|
-
|
|
3
|
-
Show how a Heinzelmännchen plugin is built: one module with an operation, settings, a health check and a submodule.
|
|
4
|
-
|
|
5
|
-
A plugin for [Heinzelmännchen](https://github.com/helmut-hoffer-von-ankershoffen/heinzel), the open-source, AI-driven
|
|
6
|
-
operating system for product development teams. It lives in
|
|
7
|
-
[heinzel-plugins](https://github.com/helmut-hoffer-von-ankershoffen/heinzel-plugins). Its earlier history is preserved
|
|
8
|
-
in heinzel-contrib and the archived heinzel-example repository.
|
|
9
|
-
|
|
10
|
-
## Install
|
|
11
|
-
|
|
12
|
-
With Heinzelmännchen installed (`uv tool install git+https://github.com/helmut-hoffer-von-ankershoffen/heinzel`):
|
|
13
|
-
|
|
14
|
-
```bash
|
|
15
|
-
hz system plugin add "heinzel-example @ git+https://github.com/helmut-hoffer-von-ankershoffen/heinzel-plugins#subdirectory=plugins/heinzel-example"
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
Running `hz system plugin add` again upgrades; `hz system plugin remove heinzel-example` removes it.
|
|
19
|
-
|
|
20
|
-
## Use
|
|
21
|
-
|
|
22
|
-
```bash
|
|
23
|
-
hz example info # this plugin, its version and the Heinzelmännchen it runs on
|
|
24
|
-
hz example hello --name Ada # a submodule collapsed into a command
|
|
25
|
-
hz example info --json # every command speaks JSON, for scripts and agents
|
|
26
|
-
hz system info # includes a section contributed by this plugin
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
## Develop
|
|
30
|
-
|
|
31
|
-
From the repository root: `make check-fast NAME=example` runs this plugin's edit loop; `make check NAME=example`
|
|
32
|
-
runs its full checks. `make build NAME=example` and `make acceptance NAME=example` verify its installed artifact.
|
|
33
|
-
The modules live in
|
|
34
|
-
`src/heinzel_example/`; read the root [AGENTS.md](../../AGENTS.md) before changing them.
|
|
35
|
-
|
|
36
|
-
Development and release commands: [repository guide](../../README.md).
|
|
37
|
-
|
|
38
|
-
Migration provenance: heinzel-contrib, before the 0.9 plugin-boundary migration.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|