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.
Files changed (44) hide show
  1. heinzel_example-0.5.2/CHANGELOG.md +21 -0
  2. heinzel_example-0.5.2/PKG-INFO +104 -0
  3. heinzel_example-0.5.2/README.md +83 -0
  4. heinzel_example-0.5.2/docs/SCREENSHOTS.md +10 -0
  5. heinzel_example-0.5.2/docs/SCREENSHOT_STORY.md +43 -0
  6. heinzel_example-0.5.2/docs/assets/cli.png +0 -0
  7. heinzel_example-0.5.2/docs/assets/screenshots/capture.json +102 -0
  8. heinzel_example-0.5.2/docs/assets/screenshots/greeting-cli.png +0 -0
  9. heinzel_example-0.5.2/docs/assets/screenshots/greeting-cli.txt +1 -0
  10. heinzel_example-0.5.2/docs/assets/screenshots/greeting-terminal.png +0 -0
  11. heinzel_example-0.5.2/docs/assets/screenshots/greeting-terminal.txt +48 -0
  12. heinzel_example-0.5.2/docs/assets/screenshots/index.html +1 -0
  13. heinzel_example-0.5.2/docs/assets/screenshots/inspector.png +0 -0
  14. heinzel_example-0.5.2/docs/assets/screenshots/inspector.txt +41 -0
  15. heinzel_example-0.5.2/docs/assets/screenshots/plugin-notice.png +0 -0
  16. heinzel_example-0.5.2/docs/assets/screenshots/plugin-notice.txt +57 -0
  17. heinzel_example-0.5.2/docs/assets/screenshots/sample-json.png +0 -0
  18. heinzel_example-0.5.2/docs/assets/screenshots/sample-json.txt +1 -0
  19. heinzel_example-0.5.2/docs/assets/screenshots/source-story.md +43 -0
  20. heinzel_example-0.5.2/docs/assets/screenshots/widget-and-status.png +0 -0
  21. heinzel_example-0.5.2/docs/assets/screenshots/widget-and-status.txt +40 -0
  22. heinzel_example-0.5.2/docs/assets/ui.png +0 -0
  23. heinzel_example-0.5.2/docs/screenshot-definition.json +7 -0
  24. heinzel_example-0.5.2/docs/screenshot_fixture.py +23 -0
  25. heinzel_example-0.5.2/docs/screenshots.toml +96 -0
  26. {heinzel_example-0.4.0 → heinzel_example-0.5.2}/plugin-lock.json +3 -1
  27. {heinzel_example-0.4.0 → heinzel_example-0.5.2}/pyproject.toml +40 -1
  28. {heinzel_example-0.4.0 → heinzel_example-0.5.2}/requirements.lock +23 -3
  29. {heinzel_example-0.4.0 → heinzel_example-0.5.2}/src/heinzel_example/__init__.py +9 -4
  30. {heinzel_example-0.4.0 → heinzel_example-0.5.2}/src/heinzel_example/views/index.js +3 -3
  31. {heinzel_example-0.4.0 → heinzel_example-0.5.2}/tests/contributions_test.py +13 -1
  32. heinzel_example-0.4.0/CHANGELOG.md +0 -8
  33. heinzel_example-0.4.0/PKG-INFO +0 -59
  34. heinzel_example-0.4.0/README.md +0 -38
  35. {heinzel_example-0.4.0 → heinzel_example-0.5.2}/.gitignore +0 -0
  36. {heinzel_example-0.4.0 → heinzel_example-0.5.2}/LICENSE +0 -0
  37. {heinzel_example-0.4.0 → heinzel_example-0.5.2}/src/heinzel_example/_models.py +0 -0
  38. {heinzel_example-0.4.0 → heinzel_example-0.5.2}/src/heinzel_example/_service.py +0 -0
  39. {heinzel_example-0.4.0 → heinzel_example-0.5.2}/src/heinzel_example/hello/__init__.py +0 -0
  40. {heinzel_example-0.4.0 → heinzel_example-0.5.2}/src/heinzel_example/py.typed +0 -0
  41. {heinzel_example-0.4.0 → heinzel_example-0.5.2}/tests/acceptance/install_test.py +0 -0
  42. {heinzel_example-0.4.0 → heinzel_example-0.5.2}/tests/conftest.py +0 -0
  43. {heinzel_example-0.4.0 → heinzel_example-0.5.2}/tests/integration/cli_test.py +0 -0
  44. {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&#x27;s native terminal." width="960">
83
+
84
+ Demo data: greet fictional Mira with structured JSON in the app&#x27;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&#x27;s native terminal." width="960">
62
+
63
+ Demo data: greet fictional Mira with structured JSON in the app&#x27;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.
@@ -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
+ }
@@ -0,0 +1 @@
1
+ text Hello, Mira!
@@ -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&#x27;s native terminal."></a><figcaption>UI · Demo data: greet fictional Mira with structured JSON in the app&#x27;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>
@@ -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
@@ -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
@@ -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.
@@ -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.1",
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.4.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.1 \
644
- --hash=sha256:aa38ed19bcc084ba42782a73255b3582283eced7ad6dddbd6695189e69adfb75 \
645
- --hash=sha256:b31553efa588ae44bc306f863c785c5333a9ecc091248c6ee68b4b6c87fdedfb
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": False, "sidebar": True})
49
+ @module.status(source="sample", order=700, slots={"footer": True, "sidebar": True})
50
50
  def status(value: int) -> StatusItem:
51
- """Render checked data through the same host slots as built-in modules."""
52
- return StatusItem(text=f"Example: {value}", icon="star", effect=Navigate(path="/?panel=example:inspector"))
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, onClose}) {
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…" : `The value is ${data}.`),
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.
@@ -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.
@@ -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