oris-skills 2.2.1 → 2.2.3

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## Unreleased
4
+
5
+ - **Settings are per-project and tiny**: moved out of the user-global `~/.oris/settings.json` into `.oris-flow/settings.json`, holding only `orisFlow.responseStyle` (`standard`/`caveman`) and `orisFlow.artifactLanguage` (document language, default `en`). The installer no longer creates a settings file.
6
+ - **Test profiles removed**: the whole profile/secret subsystem is gone — `defaultProfiles`, `profiles`, the adapter `profile` block and its env mappings, and the loop's profile-gating. Every project drives its own e2e/CI tooling; Oris stores no credentials.
7
+ - **No UI-language setting**: chat, menus, and question labels follow the language the user writes (deduced from context); only generated documents use `artifactLanguage`.
8
+ - **No refresh-policy setting**: map freshness is answered by the `headSha` anchor (`flow scan --check`); the advisory `refreshPolicy` field was dropped from the manifest and schema.
9
+ - **Questions & subagents fire reliably**: conventions now bind a platform question call (Claude `AskUserQuestion`) as a tool call rather than optional chat text, and treat entering an Oris route as the explicit request to spawn scan subagents — so gates open their UI and setup fans out by default.
10
+
3
11
  ## 2.2.1 - 2026-07-07
4
12
 
5
13
  - **Loop roles are invisible to users**: the installer no longer writes `oris-loop-{executor,verifier,doctor,debriefer}` into `~/.cursor/agents/`, `~/.claude/agents/`, or `~/.codex/agents/` — they showed up as manually invocable subagents, but the loop orchestrator never spawns them by name (it passes each loop's `prompts/<role>.md` to a generic subagent). `agents/` stays in the repo as the canonical role definitions for development. Uninstall (and therefore reinstall/upgrade) now also removes adapters left behind by earlier versions.
package/README.md CHANGED
@@ -91,9 +91,10 @@ Stop anything, anytime: `npx oris-skills loop chat --action stop`.
91
91
 
92
92
  ## Tuning
93
93
 
94
- Settings live in `~/.oris/settings.json` (`/oris-flow` → Setup language & profiles):
95
- chat and document language (`en`/`it`), test profiles, and `responseStyle: "caveman"`
96
- chat shrinks to maximum token density while documents and safety gates stay complete.
94
+ Settings live in `.oris-flow/settings.json` (`/oris-flow` → Setup): document language
95
+ (`artifactLanguage`, default `en`) and `responseStyle` (`standard`/`caveman`, where
96
+ caveman shrinks chat to maximum token density while documents and safety gates stay
97
+ complete). Chat language is deduced from your messages, not configured.
97
98
 
98
99
  ## Repository layout
99
100
 
@@ -0,0 +1,5 @@
1
+ # Architecture Decision Records
2
+
3
+ Decisions agents must not re-litigate. Format: `NNNN-short-title.md`.
4
+
5
+ Each ADR: context, decision, consequences. See `docs/architecture.md` for current principles.
@@ -14,13 +14,12 @@ The installer detects Cursor / Claude Code / Codex from `~/.cursor`, `~/.claude`
14
14
 
15
15
  ```text
16
16
  ~/.oris/oris-skills/ bundle: scripts, skills, references, agents, docs
17
- ~/.oris/settings.json user settings (created only if missing)
18
17
  ~/.cursor/skills/<name>/ Cursor skills (marker-managed)
19
18
  ~/.claude/skills/<name>/ Claude Code skills (marker-managed)
20
19
  ~/.codex/prompts/<name>.md Codex prompts pointing to the bundled SKILL.md
21
20
  ```
22
21
 
23
- Project assets live only in each repository's `.oris-flow/` (adapter, loops, runtime) plus thin hook wrappers in `.cursor/hooks/` and `.claude/hooks/` written by `npx oris-skills loop bootstrap`.
22
+ Project assets live only in each repository's `.oris-flow/` (adapter, settings, loops, runtime) plus thin hook wrappers in `.cursor/hooks/` and `.claude/hooks/` written by `npx oris-skills loop bootstrap`.
24
23
 
25
24
  ## Uninstall / reinstall
26
25
 
@@ -42,4 +42,4 @@ npx oris-skills reinstall
42
42
  ```
43
43
 
44
44
  Uninstall removes only Oris-owned paths (including legacy locations); preview with `--dry-run`.
45
- Settings (language, test profiles, `responseStyle: caveman` for ultra-short chat): `~/.oris/settings.json`, edited via `/oris-flow` → Setup.
45
+ Settings (`artifactLanguage` for document language, `responseStyle: caveman` for ultra-short chat): `.oris-flow/settings.json`, edited via `/oris-flow` → Setup. Chat language is deduced from context, not configured.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oris-skills",
3
- "version": "2.2.1",
3
+ "version": "2.2.3",
4
4
  "description": "Oris Skills: one entry point (/oris-flow), guided discovery-to-implementation flow, and self-tuning verified loops for Cursor, Claude Code, and Codex.",
5
5
  "license": "MIT",
6
6
  "author": "Davide Baldassarre",
@@ -26,9 +26,18 @@ The `oris-skills` CLI is NOT installed globally. ALWAYS invoke it as `npx oris-s
26
26
 
27
27
  ## Questions
28
28
 
29
- - ASK with the platform question UI (Cursor `AskQuestion`, Claude `AskUserQuestion`); ELSE ask plainly in chat.
29
+ - ASK through the platform's question tool Claude `AskUserQuestion`, Cursor `AskQuestion`
30
+ (Plan Mode). A question turn = ONE call to it. Chat text is a fallback, NOT a choice: use
31
+ it ONLY when no such tool is available (e.g. Cursor Agent Mode) or the question cannot fit
32
+ the tool's schema (open-ended, or more options than it allows) — then present the options
33
+ as a lettered list.
34
+ - Oris gates and interview questions ALWAYS qualify for the tool: the answer decides the
35
+ next step. NEVER skip the tool because an answer "looks like a sensible default".
36
+ - FIT the schema: question tools cap the options (typically 4, meta-options included).
37
+ MORE options → split into a two-level question (category first) or use the deliberate
38
+ text fallback above.
30
39
  - ONE question per turn. Recommended answer FIRST.
31
- - ALWAYS include, localized to `uiLanguage`:
40
+ - ALWAYS include, in the user's language:
32
41
  - `Explain the options` / `Spiega le opzioni` — explain, then re-ask the same question.
33
42
  - During interviews: `Enough questions — proceed` / `Basta domande — procedi` (early exit → go to the generation gate; NOT approval to write).
34
43
  - NEVER ask what the workspace, docs, code, or setup map already answer. Explore first.
@@ -41,12 +50,18 @@ The `oris-skills` CLI is NOT installed globally. ALWAYS invoke it as `npx oris-s
41
50
 
42
51
  ## Language
43
52
 
44
- - READ `references/settings.md` (user settings: `~/.oris/settings.json`).
45
- - Chat + questions: `uiLanguage`. Generated documents: `artifactLanguage`. Default both: `en`.
53
+ - CHAT, menus, and question labels: the language the user writes — DEDUCED from context,
54
+ no setting. NEVER ask which language to use when the conversation already shows it.
55
+ - GENERATED documents: `orisFlow.artifactLanguage` from `.oris-flow/settings.json`
56
+ (default `en`).
57
+ - Skill instructions and code stay English.
58
+ - COMMIT messages and PULL REQUEST titles/descriptions: ALWAYS English, whatever the chat
59
+ language or `artifactLanguage`. Work-item references follow the DevOps provider's
60
+ `workItemSyntax` (`references/devops.md`).
46
61
 
47
62
  ## Response style
48
63
 
49
- READ `orisFlow.responseStyle` (`standard` | `caveman`, default `standard`).
64
+ READ `orisFlow.responseStyle` from `.oris-flow/settings.json` (`standard` | `caveman`, default `standard`).
50
65
 
51
66
  `caveman` = the user pays per token; chat goes maximum density. The contract, in its own voice:
52
67
 
@@ -75,5 +90,11 @@ labels, receipts, error reports, and anything another session must read cold.
75
90
 
76
91
  ## Subagents
77
92
 
78
- - USE parallel subagents for independent scans when the platform has them (Cursor subagents, Claude Task tool).
93
+ - USE parallel subagents for independent scans when the platform's agent tool is in the
94
+ tool list (Claude `Agent` tool — formerly Task; Cursor subagents).
95
+ - The user invoking an Oris route IS the explicit request to spawn: when a route step
96
+ names subagent scans, platform guidance like "only spawn when the user asks" is
97
+ satisfied — do not skip on that ground.
98
+ - WHEN the platform has no agent tool (or spawning is blocked) → run the same scans
99
+ inline, sequentially, same coverage. Coverage never shrinks; only parallelism does.
79
100
  - KEEP subagent output compact: summaries and pointers, not raw logs.
@@ -0,0 +1,58 @@
1
+ # Oris DevOps
2
+
3
+ How Oris connects to a DevOps platform for commits, pull requests, and work items.
4
+ Swappable by design: today Azure DevOps, tomorrow Jira or GitHub — same flows, a different
5
+ provider block. Non-secret only; Oris stores NO credentials
6
+ (`references/conventions.md` `## Gates`).
7
+
8
+ ## Config surface
9
+
10
+ Resolved in order, each layer overriding the previous:
11
+
12
+ 1. Built-in Oris default (`azure-devops`, org `orislineweb`, MCP `oris-devops`).
13
+ 2. Organization: `~/.oris/devops.json` — shared defaults for everyone in the org.
14
+ 3. Repository: `.oris-flow/devops.json` — this repo's override.
15
+
16
+ Shape (`references/devops.schema.json`):
17
+
18
+ ```json
19
+ {
20
+ "version": 1,
21
+ "devops": {
22
+ "provider": "azure-devops",
23
+ "organization": "orislineweb",
24
+ "workItemSyntax": "#{id}",
25
+ "commitLanguage": "en",
26
+ "prLanguage": "en",
27
+ "mcp": {
28
+ "name": "oris-devops",
29
+ "package": "@azure-devops/mcp@2.7.0",
30
+ "domains": ["core", "work", "work-items", "repositories"]
31
+ }
32
+ }
33
+ }
34
+ ```
35
+
36
+ - `provider` — the DevOps platform. Swap this (and the `mcp` block) to move off Azure.
37
+ - `organization` — org/account slug; substituted into the MCP command.
38
+ - `workItemSyntax` — how a work item id is written in commits/PRs. `#{id}` → `#1234`.
39
+ - `commitLanguage` / `prLanguage` — always `en`; commits and PRs are English by contract.
40
+ - `mcp` — the MCP server Oris seeds (`oris-devops`) so agents can read work items and
41
+ repositories. Auth is the platform's own (PAT / sign-in), never Oris's.
42
+
43
+ ## Rules
44
+
45
+ 1. READ the resolved config before composing a commit or PR.
46
+ 2. NEVER store credentials in `.oris-flow/**`, `~/.oris/**`, or any Oris file.
47
+ 3. Missing provider auth → degrade: compose the message, tell the user, do not block.
48
+ 4. CONFIRM before writing any devops config file.
49
+
50
+ ## Never
51
+
52
+ - Put secrets or tokens in a devops config file.
53
+ - Hardcode a platform in the flows — read `provider` and act generically.
54
+
55
+ ## Done when
56
+
57
+ - [ ] Effective config resolved from default → org → repo before acting.
58
+ - [ ] No credentials written anywhere under Oris.
@@ -0,0 +1,54 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "title": "Oris DevOps Provider",
4
+ "$id": "https://oris.dev/schemas/oris-flow-devops-v1.json",
5
+ "type": "object",
6
+ "required": ["version", "devops"],
7
+ "additionalProperties": false,
8
+ "properties": {
9
+ "version": {
10
+ "type": "integer",
11
+ "const": 1
12
+ },
13
+ "devops": {
14
+ "type": "object",
15
+ "additionalProperties": false,
16
+ "properties": {
17
+ "provider": {
18
+ "type": "string",
19
+ "description": "DevOps platform id (e.g. azure-devops, github, jira). Swap this and the mcp block to change platform."
20
+ },
21
+ "organization": {
22
+ "type": "string",
23
+ "description": "Org/account slug substituted into the MCP command. Non-secret."
24
+ },
25
+ "workItemSyntax": {
26
+ "type": "string",
27
+ "description": "How a work item id is written in commits/PRs. Template with {id}, e.g. #{id} -> #1234."
28
+ },
29
+ "commitLanguage": {
30
+ "type": "string",
31
+ "minLength": 2,
32
+ "description": "Language for commit messages. Always en by contract."
33
+ },
34
+ "prLanguage": {
35
+ "type": "string",
36
+ "minLength": 2,
37
+ "description": "Language for pull request titles/descriptions. Always en by contract."
38
+ },
39
+ "mcp": {
40
+ "type": "object",
41
+ "additionalProperties": false,
42
+ "description": "MCP server Oris seeds so agents can read work items and repositories. No credentials.",
43
+ "properties": {
44
+ "name": { "type": "string" },
45
+ "package": { "type": "string" },
46
+ "domains": { "type": "array", "items": { "type": "string" } },
47
+ "command": { "type": "string" },
48
+ "args": { "type": "array", "items": { "type": "string" } }
49
+ }
50
+ }
51
+ }
52
+ }
53
+ }
54
+ }
@@ -32,7 +32,7 @@ NEVER split one feature's docs across unrelated directories.
32
32
 
33
33
  ## Rules
34
34
 
35
- 1. Language: documents in `artifactLanguage`; skill instructions stay English.
35
+ 1. Language: documents in `artifactLanguage` (default `en`); chat/UI language is deduced from context. Skill instructions and code stay English.
36
36
  2. Steps are independent: any document may be created without the previous one. State the missing source once, use the strongest confirmed source, record the gap in the document ("not available" localized). Never block on a missing predecessor.
37
37
  3. INSPECT the task folder + setup map before asking the user or writing.
38
38
  4. Every document ends with a change-history table: date | source | change | reason. Later changes rewrite the affected sections AND add a history row — no inline "changed!" notes.
@@ -4,7 +4,7 @@
4
4
  "title": "Oris Loop Repository Adapter",
5
5
  "type": "object",
6
6
  "additionalProperties": false,
7
- "required": ["$schema", "schemaVersion", "repository", "paths", "commands", "profile", "preflight"],
7
+ "required": ["$schema", "schemaVersion", "repository", "paths", "commands", "preflight"],
8
8
  "properties": {
9
9
  "$schema": {
10
10
  "const": "https://oris.dev/schemas/oris-loop-adapter-v1.json"
@@ -54,22 +54,6 @@
54
54
  "propertyNames": { "pattern": "^[a-z][a-z0-9-]*$" },
55
55
  "additionalProperties": { "type": "string", "minLength": 1 }
56
56
  },
57
- "profile": {
58
- "type": "object",
59
- "additionalProperties": false,
60
- "required": ["required", "defaultRole", "mappings"],
61
- "properties": {
62
- "required": { "type": "boolean" },
63
- "defaultRole": {
64
- "type": "string",
65
- "pattern": "^[a-z][a-zA-Z0-9]*$"
66
- },
67
- "mappings": {
68
- "type": "array",
69
- "items": { "$ref": "#/$defs/mapping" }
70
- }
71
- }
72
- },
73
57
  "preflight": {
74
58
  "type": "object",
75
59
  "additionalProperties": false,
@@ -104,23 +88,6 @@
104
88
  "minimum": 0
105
89
  }
106
90
  }
107
- },
108
- "mapping": {
109
- "type": "object",
110
- "additionalProperties": false,
111
- "required": ["env", "from", "required", "secret"],
112
- "properties": {
113
- "env": {
114
- "type": "string",
115
- "pattern": "^[A-Z_][A-Z0-9_]*$"
116
- },
117
- "from": {
118
- "type": "string",
119
- "pattern": "^[A-Za-z][A-Za-z0-9]*(\\.[A-Za-z][A-Za-z0-9]*)*$"
120
- },
121
- "required": { "type": "boolean" },
122
- "secret": { "type": "boolean" }
123
- }
124
91
  }
125
92
  }
126
93
  }
@@ -6,10 +6,10 @@ Setup map = the default project context for every Oris skill and loop. It exists
6
6
 
7
7
  | File | Scope | Purpose |
8
8
  |------|-------|---------|
9
- | `.oris-flow/manifest.json` | repo | compact index: section paths, freshness, confidence, refresh policy |
9
+ | `.oris-flow/manifest.json` | repo | compact index: section paths, freshness, confidence |
10
10
  | `.oris-flow/maps/**` | repo | short markdown maps: docs, stack, commands, code areas, tests |
11
11
  | `.oris-flow/adapter.json` | repo | loop adapter: paths, commands, model aliases |
12
- | `~/.oris/settings.json` | user | language + test profiles |
12
+ | `.oris-flow/settings.json` | repo | preferences: `responseStyle` + `artifactLanguage` (non-secret) |
13
13
  | `{tasksRoot}/{task}/…` | task | business artifacts only — `setup.tasksRoot` in the manifest, default `.oris-flow/tasks` (see `references/doc-policy.md`) |
14
14
 
15
15
  Manifest and maps are never task authority and NEVER hold secrets.
@@ -24,7 +24,6 @@ Manifest and maps are never task authority and NEVER hold secrets.
24
24
  "generatedAt": "",
25
25
  "updatedAt": "",
26
26
  "setup": { "versionControl": { "orisFlowMap": "commit" } },
27
- "refreshPolicy": {},
28
27
  "sections": {}
29
28
  }
30
29
  ```
@@ -46,7 +45,6 @@ Each section: purpose, authoritative paths, confirmed decisions, key commands/co
46
45
  2. VERIFY stale or high-risk facts against the repository before consequential actions.
47
46
  3. Loops: the orchestrator passes relevant setup-map facts into role prompts at craft time; users never repeat project facts per loop.
48
47
  4. SUGGEST `/oris-flow` → Setup refresh only when a stale gap materially affects the task.
49
- 5. Refresh policy is advisory — never a scheduler.
50
48
 
51
49
  ## Command surface
52
50
 
@@ -49,9 +49,6 @@
49
49
  "setup": {
50
50
  "$ref": "#/$defs/setup"
51
51
  },
52
- "refreshPolicy": {
53
- "$ref": "#/$defs/refreshPolicy"
54
- },
55
52
  "sections": {
56
53
  "$ref": "#/$defs/sections"
57
54
  },
@@ -106,29 +103,6 @@
106
103
  "pattern": "^[a-z][a-zA-Z0-9-]*$"
107
104
  }
108
105
  },
109
- "refreshPolicy": {
110
- "type": "object",
111
- "additionalProperties": false,
112
- "required": ["mode"],
113
- "properties": {
114
- "mode": {
115
- "type": "string",
116
- "enum": ["manual", "monthly", "after-major-refactor", "after-test-layout-change"]
117
- },
118
- "suggestAfterDays": {
119
- "type": "integer",
120
- "minimum": 1
121
- },
122
- "triggers": {
123
- "type": "array",
124
- "items": {
125
- "type": "string",
126
- "enum": ["after-major-refactor", "after-test-layout-change"]
127
- },
128
- "uniqueItems": true
129
- }
130
- }
131
- },
132
106
  "setup": {
133
107
  "type": "object",
134
108
  "additionalProperties": false,
@@ -1,36 +1,24 @@
1
1
  # Oris Settings
2
2
 
3
- User-local settings, never bundle content. Path: `~/.oris/settings.json` (all platforms).
4
- The installer creates it when missing; it NEVER overwrites an existing file.
3
+ Per-project preferences. Path: `.oris-flow/settings.json`. Small and non-secret —
4
+ chat verbosity and document language, nothing else. Missing file defaults below.
5
+ Created/edited via `/oris-flow` → Setup, or by hand.
5
6
 
6
7
  ## Shape (v1)
7
8
 
8
9
  ```json
9
10
  {
10
11
  "version": 1,
11
- "orisFlow": { "uiLanguage": "en", "artifactLanguage": "en", "responseStyle": "standard" },
12
- "defaultProfiles": { "testing": "default" },
13
- "profiles": {
14
- "default": {
15
- "environment": "local",
16
- "values": { "baseUrl": "" },
17
- "secrets": { "username": "", "password": "" },
18
- "flags": { "allowDataMutation": false }
19
- }
20
- }
12
+ "orisFlow": { "responseStyle": "standard", "artifactLanguage": "en" }
21
13
  }
22
14
  ```
23
15
 
24
- - `uiLanguage` → chat, menus, question labels, recaps (`en` | `it`, default `en`).
25
- - `artifactLanguage` → generated documents (`en` | `it`, default `en`).
26
16
  - `responseStyle` → chat verbosity (`standard` | `caveman`, default `standard`). Caveman = maximum token density in chat; contract in `references/conventions.md` `## Response style`. Documents and gates are never compressed.
27
- - `profiles` → repository-neutral test logins/config. The repo adapter maps profile fields to roles.
28
- - `flags.allowDataMutation` → data mutation allowed ONLY with `environment: local` + loopback URLs + this flag true.
17
+ - `artifactLanguage` → language for generated documents (ISO code, default `en`). Chat/UI language is NOT configured here it is deduced from the conversation.
29
18
 
30
19
  ## Rules
31
20
 
32
- 1. READ settings before the first workflow question; missing/invalid → defaults above.
21
+ 1. READ settings before the first workflow decision; missing/invalid → defaults above.
33
22
  2. Current user instructions override settings for the turn.
34
- 3. Passwords: only in this file. NEVER committed, printed, put in docs, loop state, receipts, or CLI args. Mask as `***` everywhere.
35
- 4. CONFIRM before writing settings. Update via `/oris-flow` → Setup → language & profiles.
36
- 5. In an approved loop scope, use only the profile/commands/tools the loop declares; otherwise `blocked`.
23
+ 3. Oris stores no credentials. Test/CI secrets belong to each project's own tooling — never Oris files, docs, loop state, receipts, or logs.
24
+ 4. CONFIRM before writing settings. Update via `/oris-flow` → Setup.
@@ -1,80 +1,30 @@
1
- {
2
- "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "title": "Oris Flow Settings",
4
- "type": "object",
5
- "$id": "https://oris.dev/schemas/oris-flow-settings-v1.json",
6
- "required": ["version", "orisFlow", "defaultProfiles", "profiles"],
7
- "additionalProperties": false,
8
- "properties": {
9
- "version": {
10
- "type": "integer",
11
- "const": 1
12
- },
13
- "orisFlow": {
14
- "type": "object",
15
- "required": ["uiLanguage", "artifactLanguage"],
16
- "additionalProperties": false,
17
- "properties": {
18
- "uiLanguage": {
19
- "type": "string",
20
- "enum": ["en", "it"]
21
- },
22
- "artifactLanguage": {
23
- "type": "string",
24
- "enum": ["it", "en"]
25
- },
26
- "responseStyle": {
27
- "type": "string",
28
- "enum": ["standard", "caveman"],
29
- "description": "Chat verbosity: standard prose or caveman (maximum token density; documents and gates never compressed)."
30
- }
31
- }
32
- },
33
- "defaultProfiles": {
34
- "type": "object",
35
- "minProperties": 1,
36
- "additionalProperties": {
37
- "type": "string",
38
- "minLength": 1
39
- }
40
- },
41
- "profiles": {
42
- "type": "object",
43
- "minProperties": 1,
44
- "additionalProperties": {
45
- "$ref": "#/$defs/profile"
46
- }
47
- }
48
- },
49
- "$defs": {
50
- "profile": {
51
- "type": "object",
52
- "additionalProperties": false,
53
- "required": ["environment", "values", "secrets", "flags"],
54
- "properties": {
55
- "environment": {
56
- "type": "string",
57
- "minLength": 1
58
- },
59
- "values": {
60
- "type": "object",
61
- "additionalProperties": {
62
- "type": ["string", "number", "boolean"]
63
- }
64
- },
65
- "secrets": {
66
- "type": "object",
67
- "additionalProperties": {
68
- "type": "string"
69
- }
70
- },
71
- "flags": {
72
- "type": "object",
73
- "additionalProperties": {
74
- "type": "boolean"
75
- }
76
- }
77
- }
78
- }
79
- }
80
- }
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "title": "Oris Flow Settings",
4
+ "$id": "https://oris.dev/schemas/oris-flow-settings-v1.json",
5
+ "type": "object",
6
+ "required": ["version", "orisFlow"],
7
+ "additionalProperties": false,
8
+ "properties": {
9
+ "version": {
10
+ "type": "integer",
11
+ "const": 1
12
+ },
13
+ "orisFlow": {
14
+ "type": "object",
15
+ "additionalProperties": false,
16
+ "properties": {
17
+ "responseStyle": {
18
+ "type": "string",
19
+ "enum": ["standard", "caveman"],
20
+ "description": "Chat verbosity: standard prose or caveman (maximum token density; documents and gates never compressed). Default standard."
21
+ },
22
+ "artifactLanguage": {
23
+ "type": "string",
24
+ "minLength": 2,
25
+ "description": "Language for generated documents (ISO code, e.g. en, it). Default en. Chat language is deduced from the conversation, not configured here."
26
+ }
27
+ }
28
+ }
29
+ }
30
+ }
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from "node:fs";
4
+ import os from "node:os";
5
+ import path from "node:path";
6
+
7
+ /**
8
+ * Built-in Oris default DevOps provider. Non-secret only — org and repo layers override it.
9
+ * The provider is swappable: move off Azure DevOps by overriding `provider` and `mcp`.
10
+ */
11
+ export const DEFAULT_DEVOPS = {
12
+ version: 1,
13
+ devops: {
14
+ provider: "azure-devops",
15
+ organization: "orislineweb",
16
+ workItemSyntax: "#{id}",
17
+ commitLanguage: "en",
18
+ prLanguage: "en",
19
+ mcp: {
20
+ name: "oris-devops",
21
+ package: "@azure-devops/mcp@2.7.0",
22
+ domains: ["core", "work", "work-items", "repositories"],
23
+ },
24
+ },
25
+ };
26
+
27
+ function isPlainObject(value) {
28
+ return value !== null && typeof value === "object" && !Array.isArray(value);
29
+ }
30
+
31
+ /** Deep-merge source over target; arrays and scalars replace, plain objects merge. */
32
+ function deepMerge(target, source) {
33
+ if (!isPlainObject(source)) return source;
34
+ const out = isPlainObject(target) ? { ...target } : {};
35
+ for (const [key, value] of Object.entries(source)) {
36
+ out[key] = isPlainObject(value) ? deepMerge(out[key], value) : value;
37
+ }
38
+ return out;
39
+ }
40
+
41
+ function readJson(filePath) {
42
+ try {
43
+ return JSON.parse(fs.readFileSync(filePath, "utf8"));
44
+ } catch {
45
+ return null;
46
+ }
47
+ }
48
+
49
+ /**
50
+ * Resolve the effective DevOps config: built-in default → org (`~/.oris/devops.json`) →
51
+ * repository (`.oris-flow/devops.json`). Missing or invalid layers are skipped, never fatal.
52
+ */
53
+ export function resolveDevops(repositoryRoot, options = {}) {
54
+ const home = options.home ?? os.homedir();
55
+ const orgFile = readJson(path.join(home, ".oris", "devops.json"));
56
+ const repoFile = repositoryRoot ? readJson(path.join(repositoryRoot, ".oris-flow", "devops.json")) : null;
57
+ let resolved = DEFAULT_DEVOPS;
58
+ for (const layer of [orgFile, repoFile]) {
59
+ if (isPlainObject(layer)) resolved = deepMerge(resolved, layer);
60
+ }
61
+ return resolved;
62
+ }
63
+
64
+ /**
65
+ * Build the MCP server entry for an agent config from a resolved `devops` block. Azure
66
+ * DevOps command shape by default; any provider can supply explicit `mcp.args` instead.
67
+ */
68
+ export function buildMcpServer(devops) {
69
+ const mcp = devops.mcp ?? {};
70
+ if (Array.isArray(mcp.args)) return { command: mcp.command ?? "npx", args: [...mcp.args] };
71
+ const domains = Array.isArray(mcp.domains) ? mcp.domains : [];
72
+ return { command: "npx", args: ["-y", mcp.package, devops.organization, "-d", ...domains] };
73
+ }
74
+
75
+ export function mcpServerName(devops) {
76
+ return devops.mcp?.name ?? "oris-devops";
77
+ }
@@ -8,9 +8,9 @@ export const ORIS_FLOW_TASKS_ROOT = ".oris-flow/tasks";
8
8
  export const ORIS_FLOW_ADAPTER = ".oris-flow/adapter.json";
9
9
  export const ORIS_FLOW_LOOPS_ROOT = ".oris-flow/loops";
10
10
  export const ORIS_FLOW_RUNTIME = ".oris-flow/runtime";
11
+ export const ORIS_FLOW_SETTINGS = ".oris-flow/settings.json";
11
12
  export const ORIS_HOME = path.join(os.homedir(), ".oris");
12
13
  export const ORIS_BUNDLE_ROOT = path.join(ORIS_HOME, "oris-skills");
13
- export const ORIS_SKILLS_SETTINGS = path.join(ORIS_HOME, "settings.json");
14
14
  export const ORIS_LOOP_SCHEMA = "https://oris.dev/schemas/oris-loop-adapter-v1.json";
15
15
  export const ORIS_LOOP_SCHEMA_VERSION = 1;
16
16
  export const ORIS_LOOP_DOCUMENT_VERSION = 2;