dsh-env-manager-plugin 0.0.0-stage → 0.1.0

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 (148) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +249 -2
  3. package/client.js +2581 -0
  4. package/cordis.patch.yml +4 -0
  5. package/docs/00-project/current-state.md +246 -0
  6. package/docs/00-project/glossary.md +215 -0
  7. package/docs/00-project/project-brief.md +114 -0
  8. package/docs/00-project/roadmap.md +89 -0
  9. package/docs/01-architecture/DSH_Environment_Service_Memory_Skill_Brainstorm.md +493 -0
  10. package/docs/01-architecture/api-verification.md +416 -0
  11. package/docs/01-architecture/architecture-overview.md +222 -0
  12. package/docs/01-architecture/data-model.md +930 -0
  13. package/docs/01-architecture/decisions/ADR-0001-plugin-as-bundle.md +29 -0
  14. package/docs/01-architecture/decisions/ADR-0002-file-based-storage.md +25 -0
  15. package/docs/01-architecture/decisions/ADR-0003-skill-router-over-search.md +25 -0
  16. package/docs/01-architecture/decisions/ADR-0004-typescript-host-js-client.md +31 -0
  17. package/docs/01-architecture/decisions/ADR-0005-layered-rule-resolution.md +36 -0
  18. package/docs/01-architecture/decisions/ADR-0006-credentials-as-references.md +30 -0
  19. package/docs/01-architecture/decisions/ADR-0007-session-scoped-default-environment.md +28 -0
  20. package/docs/01-architecture/decisions/ADR-0008-memory-bridge-not-second-store.md +31 -0
  21. package/docs/01-architecture/decisions/ADR-0009-client-host-http-transport.md +87 -0
  22. package/docs/01-architecture/decisions/ADR-0010-environment-plane-model.md +87 -0
  23. package/docs/01-architecture/decisions/ADR-0011-k8s-node-execution-model.md +92 -0
  24. package/docs/01-architecture/design.md +666 -0
  25. package/docs/01-architecture/detailed-design.md +961 -0
  26. package/docs/01-architecture/implementation-plan.md +323 -0
  27. package/docs/01-architecture/module-boundaries.md +306 -0
  28. package/docs/01-architecture/security-model.md +227 -0
  29. package/docs/01-architecture/storage-contract.md +224 -0
  30. package/docs/01-architecture/tool-contract.md +438 -0
  31. package/docs/01-architecture/ui-design.md +587 -0
  32. package/docs/02-harness/agent-behavior.md +36 -0
  33. package/docs/02-harness/change-snapshot-policy.md +29 -0
  34. package/docs/02-harness/client-ui-integration.md +110 -0
  35. package/docs/02-harness/context-policy.md +43 -0
  36. package/docs/02-harness/harness-standard.md +91 -0
  37. package/docs/02-harness/task-execution-policy.md +26 -0
  38. package/docs/02-harness/verification-policy.md +97 -0
  39. package/docs/03-openspec/archive-rule.md +25 -0
  40. package/docs/03-openspec/bugfix-rule.md +30 -0
  41. package/docs/03-openspec/design-rule.md +33 -0
  42. package/docs/03-openspec/openspec-usage-guide.md +31 -0
  43. package/docs/03-openspec/proposal-rule.md +70 -0
  44. package/docs/03-openspec/spec-rule.md +33 -0
  45. package/docs/03-openspec/tasks-rule.md +31 -0
  46. package/docs/04-development/coding-style.md +67 -0
  47. package/docs/04-development/dependency-policy.md +43 -0
  48. package/docs/04-development/development-guide.md +85 -0
  49. package/docs/04-development/directory-convention.md +105 -0
  50. package/docs/04-development/local-run-guide.md +55 -0
  51. package/docs/04-development/testing-guide.md +102 -0
  52. package/docs/05-domain/deployment-template.md +76 -0
  53. package/docs/05-domain/environment-template.md +165 -0
  54. package/docs/05-domain/operation-binding-template.md +55 -0
  55. package/docs/05-domain/operation-record-template.md +55 -0
  56. package/docs/05-domain/prompt-template.md +90 -0
  57. package/docs/05-domain/rule-template.md +73 -0
  58. package/docs/05-domain/service-template.md +39 -0
  59. package/docs/06-operations/deployment-guide.md +54 -0
  60. package/docs/06-operations/release.md +188 -0
  61. package/docs/06-operations/security-policy.md +53 -0
  62. package/docs/06-operations/troubleshooting.md +91 -0
  63. package/docs/07-templates/adr-template.md +21 -0
  64. package/docs/07-templates/bugfix-template.md +11 -0
  65. package/docs/07-templates/case-template.md +15 -0
  66. package/docs/07-templates/design-template.md +29 -0
  67. package/docs/07-templates/proposal-template.md +19 -0
  68. package/docs/07-templates/spec-template.md +15 -0
  69. package/docs/07-templates/tasks-template.md +12 -0
  70. package/docs/99-archive/README.md +13 -0
  71. package/docs/README.md +142 -0
  72. package/icon.svg +4 -0
  73. package/index.js +8 -0
  74. package/lib/app/app.d.ts +67 -0
  75. package/lib/app/app.js +494 -0
  76. package/lib/app/app.js.map +1 -0
  77. package/lib/config.d.ts +55 -0
  78. package/lib/config.js +42 -0
  79. package/lib/config.js.map +1 -0
  80. package/lib/domain/constants.d.ts +21 -0
  81. package/lib/domain/constants.js +59 -0
  82. package/lib/domain/constants.js.map +1 -0
  83. package/lib/domain/errors.d.ts +20 -0
  84. package/lib/domain/errors.js +22 -0
  85. package/lib/domain/errors.js.map +1 -0
  86. package/lib/domain/schemas.d.ts +28 -0
  87. package/lib/domain/schemas.js +445 -0
  88. package/lib/domain/schemas.js.map +1 -0
  89. package/lib/domain/types.d.ts +412 -0
  90. package/lib/domain/types.js +2 -0
  91. package/lib/domain/types.js.map +1 -0
  92. package/lib/index.d.ts +18 -0
  93. package/lib/index.js +89 -0
  94. package/lib/index.js.map +1 -0
  95. package/lib/logger.d.ts +8 -0
  96. package/lib/logger.js +13 -0
  97. package/lib/logger.js.map +1 -0
  98. package/lib/memory/bridge.d.ts +18 -0
  99. package/lib/memory/bridge.js +13 -0
  100. package/lib/memory/bridge.js.map +1 -0
  101. package/lib/registry/integrity.d.ts +10 -0
  102. package/lib/registry/integrity.js +204 -0
  103. package/lib/registry/integrity.js.map +1 -0
  104. package/lib/registry/registry.d.ts +14 -0
  105. package/lib/registry/registry.js +182 -0
  106. package/lib/registry/registry.js.map +1 -0
  107. package/lib/resolver/merge.d.ts +23 -0
  108. package/lib/resolver/merge.js +90 -0
  109. package/lib/resolver/merge.js.map +1 -0
  110. package/lib/resolver/resolve.d.ts +18 -0
  111. package/lib/resolver/resolve.js +288 -0
  112. package/lib/resolver/resolve.js.map +1 -0
  113. package/lib/resolver/template.d.ts +10 -0
  114. package/lib/resolver/template.js +42 -0
  115. package/lib/resolver/template.js.map +1 -0
  116. package/lib/router/params.d.ts +3 -0
  117. package/lib/router/params.js +83 -0
  118. package/lib/router/params.js.map +1 -0
  119. package/lib/router/router.d.ts +11 -0
  120. package/lib/router/router.js +204 -0
  121. package/lib/router/router.js.map +1 -0
  122. package/lib/session/session.d.ts +16 -0
  123. package/lib/session/session.js +64 -0
  124. package/lib/session/session.js.map +1 -0
  125. package/lib/skill.d.ts +17 -0
  126. package/lib/skill.js +56 -0
  127. package/lib/skill.js.map +1 -0
  128. package/lib/storage/atomic.d.ts +10 -0
  129. package/lib/storage/atomic.js +107 -0
  130. package/lib/storage/atomic.js.map +1 -0
  131. package/lib/storage/paths.d.ts +10 -0
  132. package/lib/storage/paths.js +50 -0
  133. package/lib/storage/paths.js.map +1 -0
  134. package/lib/storage/records.d.ts +16 -0
  135. package/lib/storage/records.js +112 -0
  136. package/lib/storage/records.js.map +1 -0
  137. package/lib/storage/sessions.d.ts +17 -0
  138. package/lib/storage/sessions.js +65 -0
  139. package/lib/storage/sessions.js.map +1 -0
  140. package/lib/tools/tools.d.ts +14 -0
  141. package/lib/tools/tools.js +472 -0
  142. package/lib/tools/tools.js.map +1 -0
  143. package/lib/transport/http.d.ts +3 -0
  144. package/lib/transport/http.js +217 -0
  145. package/lib/transport/http.js.map +1 -0
  146. package/locale/en.json +6 -0
  147. package/locale/zh.json +6 -0
  148. package/package.json +97 -4
@@ -0,0 +1,43 @@
1
+ # Dependency Policy
2
+
3
+ ## Runtime dependencies
4
+
5
+ Keep the set minimal and justified:
6
+
7
+ | Package | Why |
8
+ |---|---|
9
+ | `zod` | schema validation for records and tool inputs |
10
+ | `yaml` | YAML parse/serialize with typed results |
11
+ | `@deepseek-ai/schemastery` | `Config` schema for the Host plugin |
12
+
13
+ Anything else needs a proposal that explains why the standard library and the three
14
+ packages above are insufficient.
15
+
16
+ DSH-provided packages (`@deepseek-ai/dsh-tools`, `@deepseek-ai/dsh-llm`, `@deepseek-ai/cordis`) are
17
+ peers, supplied by the profile; never bundle them.
18
+
19
+ ## Development dependencies
20
+
21
+ | Package | Why |
22
+ |---|---|
23
+ | `typescript` | Host build |
24
+ | `vitest` | tests |
25
+
26
+ Optional, with justification: `@types/node`, a linter, a formatter.
27
+
28
+ ## Rules
29
+
30
+ 1. No dependency that duplicates DSH-provided services (fs, credentials, approval, storage).
31
+ 2. No database driver.
32
+ 3. No client bundler unless a new ADR accepts it.
33
+ 4. No native modules unless there is no alternative.
34
+ 5. Check the license before adding.
35
+ 6. Prefer a small maintained package over a large framework.
36
+
37
+ ## Adding a dependency
38
+
39
+ 1. Write an OpenSpec proposal or a task entry.
40
+ 2. State the capability gap.
41
+ 3. State alternatives considered.
42
+ 4. Add it to `package.json` and the lockfile.
43
+ 5. Mention it in `docs/01-architecture/design.md` §15.4 if it changes the build.
@@ -0,0 +1,85 @@
1
+ # Development Guide
2
+
3
+ > Status: this guide describes the V1 target. The repository currently ships the JavaScript skeleton; `src/`, `lib/`, `tsconfig.json` and the npm scripts are added during V1 implementation. See `docs/00-project/current-state.md`.
4
+
5
+ ## Prerequisites
6
+
7
+ - Node.js matching the DSH runtime
8
+ - npm
9
+
10
+ ## First Run
11
+
12
+ ```bash
13
+ npm install
14
+ npm run build
15
+ npm test
16
+ ```
17
+
18
+ ## Project Layout
19
+
20
+ ```text
21
+ dsh-env-manager/
22
+ ├── index.js # Host entry shim over lib/index.js
23
+ ├── client.js # Client module (plain JS)
24
+ ├── cordis.patch.yml # Cordis patch
25
+ ├── package.json # Bundle manifest
26
+ ├── tsconfig.json # Host build config
27
+ ├── src/ # TypeScript host sources
28
+ ├── lib/ # Build output (git-ignored)
29
+ ├── locale/ # Display metadata
30
+ ├── docs/ # Project documentation
31
+ ├── data/ # Runtime registry data (git-ignored)
32
+ └── tests/ # Vitest tests
33
+ ```
34
+
35
+ ## Build
36
+
37
+ ```bash
38
+ npm run build # tsc -p tsconfig.json
39
+ npm run build:watch # optional watch mode
40
+ ```
41
+
42
+ The Host entry `index.js` re-exports `lib/index.js`. Do not edit `lib/` by hand.
43
+
44
+ ## Test
45
+
46
+ ```bash
47
+ npm test # vitest run
48
+ npm run test:watch # vitest
49
+ ```
50
+
51
+ ## Install in a DSH Profile
52
+
53
+ In a DSH session, call the `plugin_manager` tool with `action: install_bundle` and the absolute repository path as `target`. Restart DSH if the bundle was already installed.
54
+
55
+ Do not use `dsh plugin add` for bundle selection; that forwards to pnpm only.
56
+
57
+ ## Development Loop
58
+
59
+ 1. Read the relevant docs (`docs/README.md` decides which).
60
+ 2. Change `src/` or `client.js`.
61
+ 3. Build and test.
62
+ 4. Reinstall the bundle to see Host/Client changes.
63
+ 5. Update `docs/00-project/current-state.md`.
64
+
65
+ ## Client Changes
66
+
67
+ `client.js` is plain JavaScript and needs no build. The Host serves it as the bundle's `./client` export.
68
+
69
+ Keep the module-loader wrapper intact:
70
+
71
+ ```js
72
+ window.__ModuleLoader__.load({ id: 'dsh-env-manager', factory(require) { ... } })
73
+ ```
74
+
75
+ ## Data Directory
76
+
77
+ Do not commit `data/`. It is created on first run at the resolved `dataDir`; the startup log reports the path.
78
+
79
+ ## Updating Docs
80
+
81
+ After every meaningful change update:
82
+
83
+ - `docs/00-project/current-state.md`
84
+ - the matching architecture document when behavior or schemas changed
85
+ - OpenSpec artifacts when used
@@ -0,0 +1,105 @@
1
+ # Directory Convention
2
+
3
+ > Status: target layout for V1. Directories marked as V1 are created during implementation; see `docs/00-project/current-state.md`.
4
+
5
+ ## Root
6
+
7
+ | Path | Purpose |
8
+ |---|---|
9
+ | `index.js` | Host entry shim; re-exports `lib/index.js` |
10
+ | `client.js` | Client module (plain JS, module-loader format) |
11
+ | `cordis.patch.yml` | Cordis bundle patch |
12
+ | `package.json` | Bundle manifest, scripts, dependencies |
13
+ | `tsconfig.json` | Host build configuration |
14
+ | `lib/` | Build output; git-ignored |
15
+ | `src/` | TypeScript Host sources |
16
+ | `tests/` | Vitest tests and fixtures |
17
+ | `data/` | Runtime registry data; git-ignored |
18
+ | `locale/` | `en.json`, `zh.json` |
19
+ | `docs/` | Project documentation |
20
+ | `icon.svg` | Plugin icon |
21
+
22
+ ## `src/`
23
+
24
+ ```text
25
+ src/
26
+ ├── index.ts # apply(): wiring, tools, HTTP route
27
+ ├── config.ts # schemastery Config
28
+ ├── logger.ts # ctx logger wrapper
29
+ ├── domain/
30
+ │ ├── types.ts # interfaces and enums
31
+ │ ├── schemas.ts # Zod schemas, parseRecord
32
+ │ ├── constants.ts # operation ids, limits, patterns
33
+ │ └── errors.ts # EnvManagerError, codes
34
+ ├── storage/
35
+ │ ├── paths.ts # dataDir resolution, id/path guards
36
+ │ ├── atomic.ts # temp+fsync+rename write, backups
37
+ │ ├── records.ts # read/write/delete one record
38
+ │ ├── sessions.ts # session state files
39
+ │ └── layout.ts # directory creation, tmp cleanup
40
+ ├── registry/
41
+ │ ├── registry.ts # load, snapshot, lookup, reload
42
+ │ ├── aliases.ts # alias index
43
+ │ └── integrity.ts # referential integrity diagnostics
44
+ ├── resolver/
45
+ │ ├── template.ts # ${...} parsing and substitution
46
+ │ ├── graph.ts # reference graph, cycles
47
+ │ ├── layers.ts # build ordered layers
48
+ │ ├── merge.ts # field-level merge
49
+ │ ├── context.ts # ServiceContext assembly
50
+ │ └── provenance.ts # provenance construction
51
+ ├── router/
52
+ │ ├── match.ts # match level classification
53
+ │ ├── router.ts # selection, conflicts
54
+ │ ├── skills.ts # SkillDirectory adapter
55
+ │ ├── policy.ts # approval and production rules
56
+ │ └── parameters.ts # parameter mapping
57
+ ├── session/
58
+ │ └── session-context.ts
59
+ ├── app/
60
+ │ ├── app.ts # use cases shared by tools and HTTP
61
+ │ └── actor.ts # 'agent' | 'ui' policy
62
+ ├── tools/
63
+ │ ├── define.ts # shared schemas and render helpers
64
+ │ ├── approval.ts # ctx.approval wrapper
65
+ │ ├── read.ts # env_list/get/find/get_context
66
+ │ ├── resolve.ts # env_resolve/resolve_operation
67
+ │ ├── write.ts # env_save/delete/set_context
68
+ │ └── validate.ts # env_validate
69
+ ├── transport/
70
+ │ ├── route.ts # webServer registration, body handling
71
+ │ ├── auth.ts # header, origin, size checks
72
+ │ ├── ops.ts # op table → app calls
73
+ │ └── envelope.ts # { ok, data } / { ok:false, error }
74
+ └── memory-bridge/
75
+ ├── contract.ts
76
+ └── null-adapter.ts
77
+ ```
78
+
79
+ `logger.ts` sits at the root because every module may log; it must not import them.
80
+
81
+ ## `tests/`
82
+
83
+ ```text
84
+ tests/
85
+ ├── domain/
86
+ ├── storage/
87
+ ├── registry/
88
+ ├── resolver/
89
+ ├── router/
90
+ ├── session/
91
+ ├── app/
92
+ ├── tools/
93
+ ├── http/
94
+ └── fixtures/
95
+ ```
96
+
97
+ - One test file per module: `<module>.test.ts`.
98
+ - Fixtures are small YAML files with obviously fake values.
99
+ - Never commit real hostnames, IPs, URLs or credentials.
100
+
101
+ ## Adding a module
102
+
103
+ 1. It must fit an existing boundary in `module-boundaries.md`.
104
+ 2. A new boundary needs an ADR.
105
+ 3. Update the tree in this document and in `AGENTS.md`.
@@ -0,0 +1,55 @@
1
+ # Local Run Guide
2
+
3
+ ## Build
4
+
5
+ ```bash
6
+ npm install
7
+ npm run build
8
+ ```
9
+
10
+ ## Install in a DSH Profile
11
+
12
+ In a DSH session, call the `plugin_manager` tool:
13
+
14
+ ```text
15
+ action: install_bundle
16
+ target: <absolute path to this repository>
17
+ ```
18
+
19
+ Restart DSH if the bundle was already installed before this change.
20
+
21
+ ## Verify Installation
22
+
23
+ Ask `plugin_manager` for `action: list_bundles`, then confirm the bundle appears.
24
+
25
+ Then check that the tools are available: ask the Agent to call `env_list`; it should return an empty list rather than an unknown-tool error.
26
+
27
+ ## Where the data lives
28
+
29
+ The Host reports the resolved `dataDir` once at startup. On first run the directories are created:
30
+
31
+ ```text
32
+ <dataDir>/environments services deployments rules operations sessions
33
+ ```
34
+
35
+ Put a sample environment there or use `env_save`.
36
+
37
+ ## Development loop
38
+
39
+ 1. Edit `src/`.
40
+ 2. `npm run build`.
41
+ 3. Reinstall the bundle.
42
+ 4. Restart DSH (Host code changes need a fresh module generation).
43
+ 5. Call the tool again.
44
+
45
+ `client.js` changes need the same reinstall; they do not require a build.
46
+
47
+ ## Uninstall
48
+
49
+ Call `plugin_manager` with `action: remove_bundle` and `target: dsh-env-manager-plugin`.
50
+
51
+ Registry data under `dataDir` is not removed automatically. Back it up before deleting the profile.
52
+
53
+ ## Troubleshooting
54
+
55
+ See `06-operations/troubleshooting.md`.
@@ -0,0 +1,102 @@
1
+ # Testing Guide
2
+
3
+ ## Framework
4
+
5
+ Vitest, with TypeScript sources tested directly (no build required for tests).
6
+
7
+ ## Commands
8
+
9
+ ```bash
10
+ npm test # run once
11
+ npm run test:watch # watch mode
12
+ ```
13
+
14
+ ## Test Organization
15
+
16
+ ```text
17
+ tests/
18
+ ├── domain/schemas.test.ts
19
+ ├── storage/records.test.ts
20
+ ├── storage/atomic.test.ts
21
+ ├── registry/registry.test.ts
22
+ ├── resolver/template.test.ts
23
+ ├── resolver/layers.test.ts
24
+ ├── resolver/context.test.ts
25
+ ├── router/match.test.ts
26
+ ├── router/router.test.ts
27
+ ├── session/session-context.test.ts
28
+ ├── app/app.test.ts
29
+ ├── tools/read.test.ts
30
+ ├── tools/write.test.ts
31
+ └── http/route.test.ts
32
+ ```
33
+
34
+ ## What to test
35
+
36
+ ### `domain`
37
+ - Valid record passes; unknown field fails.
38
+ - Id pattern and `schemaVersion` enforcement.
39
+ - Discriminated unions reject mismatched `runtimeMode`/`location.kind`.
40
+
41
+ ### `storage`
42
+ - Atomic write leaves no temp file.
43
+ - Read tolerates missing directory and invalid YAML.
44
+ - Backup pruning keeps at most 5.
45
+ - Concurrent writes serialize in-process.
46
+
47
+ ### `registry`
48
+ - Load, lookup by id and alias.
49
+ - Duplicate id detection.
50
+ - Referential integrity: missing environment/service/host/cluster/rule profile.
51
+ - Invalid file is skipped, not deleted.
52
+
53
+ ### `resolver`
54
+ - Layer precedence: service < environment < deployment.
55
+ - Field-level merge keeps unrelated fields.
56
+ - Provenance: `definedBy`, `inputs`, `shadowed` for the worked example in design §6.9.
57
+ - Undefined variable, cycle, path traversal, type mismatch.
58
+ - Only the runtime's log source and class location are resolved.
59
+
60
+ ### `router`
61
+ - Each match level, in isolation and in combination.
62
+ - Highest level wins; lower levels ignored.
63
+ - Same-level conflict lists all candidates and selects none.
64
+ - Missing skill, source mismatch, provider mismatch.
65
+ - Unknown/incomplete skill registry degrades to `'unknown'` plus warning.
66
+ - Production denial and `requiresApproval` defaults.
67
+ - Parameter mapping, including failure on unresolved reference.
68
+
69
+ ### `session`
70
+ - Set, get, clear.
71
+ - Two sessions do not interfere.
72
+ - Corrupt file is treated as "no default" with `persisted: false`.
73
+
74
+ ### `app`
75
+ - Save→get round trip; `created` flag.
76
+ - Delete refused when referenced (`RECORD_IN_USE`).
77
+ - Dry-run writes nothing.
78
+ - UI actor cannot write production by default.
79
+ - `find` matches id, name and alias.
80
+
81
+ ### `tools`
82
+ - Success value matches the declared `output.schema`.
83
+ - Failures throw `EnvManagerError` with the expected code.
84
+ - No credential value ever appears in output (assert on serialized JSON).
85
+ - Invalid id error code.
86
+ - `env_validate` does not write.
87
+ - Approval denial produces `POLICY_DENIED` and no file change.
88
+
89
+ ### `http`
90
+ - Missing header → 403; foreign origin → 403; GET → 405; oversize → 413.
91
+ - Unknown op → 400; not found → 404; conflict → 409; production UI write → 403.
92
+ - Success envelope is `{ ok: true, data }` and never leaks a stack.
93
+
94
+ ## Fixtures
95
+
96
+ - Under `tests/fixtures/`, one directory per scenario.
97
+ - Fake values only: `test-a`, `10.0.0.x`, `example.internal`, `cred-test-*`.
98
+ - A fixture that needs a secret-like string must use an obvious placeholder and must not be a real credential.
99
+
100
+ ## Coverage expectations
101
+
102
+ No numeric gate in V1. The resolver, router and storage modules are expected to be near-complete because they are pure and cheap to test. The Client UI is verified manually.
@@ -0,0 +1,76 @@
1
+ # Deployment Binding Template
2
+
3
+ Copy into `<dataDir>/deployments/<id>.yaml`.
4
+
5
+ A service may have several bindings in one environment. Use distinct ids and a `name` to tell them apart.
6
+
7
+ ## Kubernetes
8
+
9
+ ```yaml
10
+ id: deploy-001
11
+ schemaVersion: 1
12
+ name: aicoservice-test-a
13
+ environmentId: test-a
14
+ serviceId: aicoservice
15
+ runtimeMode: kubernetes
16
+ location:
17
+ kind: kubernetes
18
+ clusterRef: k8s-01
19
+ namespace: dv-sop
20
+ workload:
21
+ kind: Deployment
22
+ name: aicoservice
23
+ container: aicoservice
24
+ variables:
25
+ replicaCount: 2
26
+ ruleOverrides:
27
+ logSources:
28
+ kubernetes:
29
+ kind: pod-logs
30
+ namespace: dv-sop
31
+ workload: aicoservice
32
+ createdAt: 2026-11-01T03:00:00.000Z
33
+ updatedAt: 2026-11-01T03:00:00.000Z
34
+ ```
35
+
36
+ ## Native
37
+
38
+ ```yaml
39
+ id: deploy-002
40
+ schemaVersion: 1
41
+ environmentId: test-a
42
+ serviceId: aicoservice
43
+ runtimeMode: native
44
+ location:
45
+ kind: native
46
+ hostRef: host-001
47
+ installDir: /opt/company/services/aicoservice
48
+ serviceName: aicoservice.service
49
+ createdAt: 2026-11-01T03:00:00.000Z
50
+ updatedAt: 2026-11-01T03:00:00.000Z
51
+ ```
52
+
53
+ ## Docker
54
+
55
+ ```yaml
56
+ id: deploy-003
57
+ schemaVersion: 1
58
+ environmentId: test-a
59
+ serviceId: aicoservice
60
+ runtimeMode: docker
61
+ location:
62
+ kind: docker
63
+ hostRef: host-001
64
+ containerName: aicoservice
65
+ image: registry.example.internal/team/aicoservice:latest
66
+ createdAt: 2026-11-01T03:00:00.000Z
67
+ updatedAt: 2026-11-01T03:00:00.000Z
68
+ ```
69
+
70
+ ## Notes
71
+
72
+ - `runtimeMode` must equal `location.kind`.
73
+ - `hostRef` and `clusterRef` resolve inside the referenced environment only.
74
+ - `variables` are deployment-level user variables; they win over environment-level variables for that field.
75
+ - `ruleOverrides` is field-level: overriding `logSources` does not erase `paths`.
76
+ - If a service has several bindings and the caller omits `deploymentId`, the resolver fails with `DEPLOYMENT_AMBIGUOUS` rather than guessing.
@@ -0,0 +1,165 @@
1
+ # Environment Template
2
+
3
+ Copy into `<dataDir>/environments/<id>.yaml` and replace the example values.
4
+
5
+ ```yaml
6
+ id: test-a
7
+ schemaVersion: 1
8
+ name: Test Environment A
9
+ aliases: [ta, test-a]
10
+ category: test # dev | test | staging | production | custom
11
+ description: Main test environment for aicoservice
12
+
13
+ roles:
14
+ - id: management
15
+ name: Management Plane
16
+ description: Admin plane and control entry points
17
+ - id: business
18
+ name: Business Plane
19
+ description: Business traffic and workloads
20
+ - id: database
21
+ name: Database
22
+ description: Database tier (primary/replica/sharding detail is Phase 2)
23
+ - id: extension
24
+ name: Expansion / other
25
+ description: Expansion nodes and unclassified workloads
26
+
27
+ hosts:
28
+ - id: host-001
29
+ name: test-a-node-01
30
+ kind: vm
31
+ os: ubuntu-22.04
32
+ platform: Linux / x86_64
33
+ ip: 10.0.1.10
34
+ sshPort: 22
35
+ roles: [management, business] # co-location: one host, two roles
36
+ access: [ssh]
37
+ adminUser: root
38
+ isActive: true
39
+ credentialRef: cred-test-a-root
40
+ accounts:
41
+ - id: root
42
+ username: root
43
+ purpose: system administration
44
+ protocol: ssh
45
+ port: 22
46
+ authType: private-key
47
+ credentialRef: cred-test-a-root
48
+ lastLoginAt: 2026-10-31T08:12:00.000Z
49
+ lastLoginFrom: 10.0.8.21
50
+ - id: console
51
+ username: ops
52
+ purpose: business web console
53
+ protocol: web
54
+ loginUrl: https://test-a.example.internal/login
55
+ authType: password
56
+ credentialRef: env-manager/test-a/console
57
+ - id: db-01
58
+ name: test-a-db-01
59
+ kind: physical
60
+ platform: Linux / x86_64
61
+ ip: 10.0.1.30
62
+ sshPort: 22
63
+ roles: [database]
64
+ access: [ssh]
65
+ adminUser: root
66
+ isActive: true
67
+ note: primary placeholder; topology is Phase 2
68
+ - id: k8s-aio-01
69
+ name: test-a-k8s-aio-01
70
+ kind: k8s-all-in-one # control plane + worker on one machine
71
+ platform: Linux / x86_64
72
+ ip: 10.0.1.20
73
+ sshPort: 22
74
+ roles: [management, business]
75
+ access: [ssh, kubectl, docker]
76
+ clusterRef: k8s-01
77
+ adminUser: root
78
+ isActive: true
79
+ note: kubeconfig stays behind the cluster credentialRef
80
+ - id: pod-host-01
81
+ name: test-a-pod-host-01
82
+ kind: pod-host # machine running Pods; operate with docker exec
83
+ platform: Linux / x86_64
84
+ ip: 10.0.1.21
85
+ sshPort: 22
86
+ roles: [business]
87
+ access: [ssh, docker]
88
+ clusterRef: k8s-01
89
+ adminUser: root
90
+ isActive: true
91
+ note: Pods are workloads; this record is the host, not an individual Pod
92
+
93
+ clusters:
94
+ - id: k8s-01
95
+ name: test-a-k8s
96
+ kind: kubernetes
97
+ topology: all-in-one # all-in-one | separate | external
98
+ apiEndpoint: https://10.0.1.20:6443
99
+ namespaces: [dv-sop]
100
+ credentialRef: cred-test-a-kubeconfig
101
+
102
+ endpoints:
103
+ - id: ep-ssh-01
104
+ kind: ssh
105
+ hostRef: host-001
106
+ port: 22
107
+ credentialRef: cred-test-a-root
108
+ - id: ep-web-01
109
+ kind: web
110
+ url: https://test-a.example.internal
111
+
112
+ loginRecords:
113
+ - id: login-0001
114
+ at: 2026-10-31T08:12:00.000Z
115
+ username: root
116
+ hostRef: host-001
117
+ accountId: root
118
+ protocol: ssh
119
+ sourceIp: 10.0.8.21
120
+ result: success # success | failure
121
+ note: jump-host session
122
+
123
+ createdAt: 2026-11-01T03:00:00.000Z
124
+ updatedAt: 2026-11-01T03:00:00.000Z
125
+ ```
126
+
127
+ ## Notes
128
+
129
+ - `id` must match the file name.
130
+ - One environment is one network and one configuration page. Its management, business,
131
+ database and expansion planes are role views over the same `hosts[]`, not separate
132
+ environments. The UI shows a node in every plane it serves.
133
+ - `roles` must contain at least one entry, and every `hosts[].roles` value must reference a
134
+ declared `roles[].id`. A host must declare at least one role. The standard ids are
135
+ `management`, `business`, `database` and `extension`; custom ids are allowed.
136
+ - A host that serves two planes is one entry with two roles; do not duplicate it.
137
+ - `hosts[].kind` is one of `vm`, `physical`, `k8s-all-in-one`, `k8s-worker` or `pod-host`;
138
+ missing means `vm`. `k8s-all-in-one` means the control plane and worker share a machine.
139
+ `pod-host` means the machine runs Pods and is operated with `docker exec`; it is still one
140
+ host, not one entry per Pod.
141
+ - `hosts[].access` records the command surfaces present on the machine: `ssh`, `kubectl`,
142
+ `docker`. It is metadata, not an authorization grant. The form pre-fills defaults; the
143
+ values in YAML are authoritative.
144
+ - `k8s-all-in-one` and `k8s-worker` require `clusterRef` to an existing cluster.
145
+ `pod-host` may omit it for a Docker-only machine outside the cluster. Any `clusterRef`
146
+ must resolve within this environment.
147
+ - `clusters[].topology` is `all-in-one`, `separate` or `external`; it is descriptive and
148
+ optional. Per-host `kind` is authoritative.
149
+ - `endpoints[].hostRef` / `clusterRef` must resolve within this environment.
150
+ - `credentialRef` is a reference only; never put a value here. The same rule applies to
151
+ every `accounts[].credentialRef`.
152
+ - `category: production` triggers the approval gate on management writes.
153
+ - `accounts[]` is capped at 50 per host; `loginRecords[]` is capped at 200 per
154
+ environment. Login records may reference a host and an account on that host.
155
+ - `accounts[].loginUrl` is the web console entry URL for a management or business login;
156
+ `username` is the login name. It must be an absolute `http(s)` URL. The password is never
157
+ stored here: the UI writes it to the DSH credential service and keeps only `credentialRef`.
158
+ - `loginRecords` are audit context, not a replacement for a PAM/SIEM system. Keep only
159
+ the fields needed by DSH; do not copy session recordings or credentials into YAML.
160
+ - The panel's batch import writes one node per line as
161
+ `IP,name,roles,port,user`; use `|` or `/` between roles. It creates generic `vm` nodes
162
+ with `access: [ssh]`, never accepts passwords, and leaves Kubernetes/Pod-host
163
+ classification to the node form or YAML.
164
+ - Database primary/replica/sharding topology is not modeled in Phase 1. Use the
165
+ `database` role plus a node note; a later schema may add topology metadata.
@@ -0,0 +1,55 @@
1
+ # Operation Binding Template
2
+
3
+ Copy into `<dataDir>/operations/<id>.yaml`.
4
+
5
+ ```yaml
6
+ id: binding-001
7
+ schemaVersion: 1
8
+ operation: redeploy # standard id or custom id
9
+ match:
10
+ environmentId: test-a
11
+ serviceId: aicoservice
12
+ skill:
13
+ name: redeploy-k8s-service
14
+ expectedSource: null # optional SkillSummary.source constraint
15
+ expectedProvider: null # optional SkillSummary.provider constraint
16
+ parameters:
17
+ namespace: ${deployment.location.namespace}
18
+ workload: ${deployment.location.workload.name}
19
+ cluster: ${deployment.location.clusterRef}
20
+ policy:
21
+ requiresApproval: true
22
+ allowProduction: false
23
+ enabled: true
24
+ createdAt: 2026-11-01T03:00:00.000Z
25
+ updatedAt: 2026-11-01T03:00:00.000Z
26
+ ```
27
+
28
+ ## Match levels
29
+
30
+ | Level | Selectors present |
31
+ |---|---|
32
+ | `deployment` | `deploymentId` |
33
+ | `environment-service` | `environmentId` + `serviceId` |
34
+ | `service` | `serviceId` |
35
+ | `category-mode` | `serviceCategory` + `deploymentMode` |
36
+ | `global` | none (empty `match: {}`) |
37
+
38
+ Every declared selector must match. The highest eligible level wins. Two eligible bindings at the same level are a conflict, never a coin flip.
39
+
40
+ A `match` must be exactly one of these five shapes. For example `environmentId` alone, or `environmentId` + `deploymentMode`, is invalid (`RECORD_INVALID`).
41
+
42
+ ## Standard operations
43
+
44
+ ```text
45
+ install, deploy, redeploy, replace, restart, upgrade, rollback, uninstall,
46
+ collect-logs, health-check, inspect, upload, download
47
+ ```
48
+
49
+ Custom operations are allowed but must be bound explicitly.
50
+
51
+ ## Policy
52
+
53
+ - Write operations default to `requiresApproval: true`.
54
+ - `allowProduction` defaults to `false`.
55
+ - A binding is discovery information. It does not execute anything.