Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
3d6b2f5
chore(sync): carry beta back into development
github-actions[bot] Aug 30, 2026
2781f63
Merge pull request #694 from ConductionNL/sync/beta-to-development-20…
rubenvdlinde Aug 30, 2026
7d6f59d
build(deps-dev): bump css-loader from 7.1.4 to 7.1.5 (#692)
dependabot[bot] Aug 30, 2026
d6e49f3
chore(dependabot): hold back vue-router 5 as well (#701)
rubenvdlinde Aug 30, 2026
b8863b8
docs(dependabot): correct the vue-router holdback to what was measure…
rubenvdlinde Aug 30, 2026
35fcf01
chore(release): sync main back into development
github-actions[bot] Aug 31, 2026
4406b13
fix(deps): put the babel set back on 7, which webpack-vue-config requ…
rubenvdlinde Aug 31, 2026
601d858
chore(sync): carry main back into beta
github-actions[bot] Aug 31, 2026
3c49285
Merge pull request #711 from ConductionNL/sync/main-to-beta-202608310…
rubenvdlinde Aug 31, 2026
46d8f69
chore(sync): carry beta back into development
github-actions[bot] Aug 31, 2026
5210640
Merge pull request #712 from ConductionNL/sync/beta-to-development-20…
rubenvdlinde Aug 31, 2026
7c6a9d0
chore(deps): take @conduction/nextcloud-vue 2.25.1 for the KPI card (…
rubenvdlinde Aug 31, 2026
a516bff
Merge pull request #708 from ConductionNL/sync/main-to-development-0.…
rubenvdlinde Aug 31, 2026
af9f053
chore(release): 0.1.43-unstable.20260831014138 (#716)
github-actions[bot] Aug 31, 2026
6a1df89
chore(deps): refresh the shared Conduction locks (#717)
rubenvdlinde Aug 31, 2026
95c28c9
chore(deps): take @conduction/nextcloud-vue 2.27.0 (#720)
rubenvdlinde Aug 31, 2026
42fbd94
Merge pull request #698 from ConductionNL/development
rubenvdlinde Aug 31, 2026
16da32d
chore(release): sync beta back into development
github-actions[bot] Aug 31, 2026
ca8adbb
fix(composer): declare ext-xsl so dependabot can resolve (#722)
rubenvdlinde Aug 31, 2026
f25713f
Merge pull request #724 from ConductionNL/sync/beta-to-development-0.…
rubenvdlinde Aug 31, 2026
8973664
chore(deps): take @conduction/nextcloud-vue 2.27.2 (#728)
rubenvdlinde Aug 31, 2026
ddeaf68
chore(release): 0.1.44-unstable.20260831115157 (#730)
github-actions[bot] Aug 31, 2026
01275d2
fix(deps): make the npm overrides follow their direct dependency (#731)
rubenvdlinde Aug 31, 2026
0f242f9
fix(e2e): observe the dictation banner inside the 6s it exists (#733)
rubenvdlinde Aug 31, 2026
fb5b42a
chore(release): 0.1.45-unstable.20260831174250 (#734)
github-actions[bot] Aug 31, 2026
b0f1884
fix(dashboard): drop the second Refresh from the dashboard header (#735)
rubenvdlinde Sep 1, 2026
15bde2d
chore(icons): adopt the Tier B vocabulary in full (#736)
rubenvdlinde Sep 1, 2026
25826d9
chore(release): 0.1.46-unstable.20260901051841 (#738)
github-actions[bot] Sep 1, 2026
8b2b209
chore(lint): let the linter see tests/ and scripts/ (#739)
rubenvdlinde Sep 1, 2026
f29840f
fix(router): resolve deep links in both URL forms (#741)
rubenvdlinde Sep 1, 2026
91bc82d
chore(flows): finish the agentflow retirement (#743)
rubenvdlinde Sep 2, 2026
d042933
feat(approvals): converge the approval gate onto OpenRegister's task …
rubenvdlinde Sep 2, 2026
5457350
feat(schedules): hand the schedule clock to OpenRegister's flow engin…
rubenvdlinde Sep 2, 2026
5d8ea34
Takes nextcloud-vue 2.31.1 so a hovered KPI tile stops drawing a card…
rubenvdlinde Sep 2, 2026
96f14c9
fix: publish schedule mirrors for the version pin, and stop the chat …
rubenvdlinde Sep 2, 2026
de5bf24
fix(nav): move Store into the footer chrome (#758)
rubenvdlinde Sep 3, 2026
cdd799b
fix(ci): a standing release PR ran every development push twice
rubenvdlinde Sep 3, 2026
ed5d9ca
feat(nav): give hermiq a Reports page, from the report it already had…
rubenvdlinde Sep 3, 2026
722e4fc
fix(e2e): make the chrome specs pass in a real browser
rubenvdlinde Sep 3, 2026
2350fdb
Merge pull request #767 from ConductionNL/fix/app-chrome-spec-selectors
rubenvdlinde Sep 4, 2026
b3e6ec4
build(deps-dev): bump phpstan/phpstan from 2.2.9 to 2.2.12 (#763)
dependabot[bot] Sep 4, 2026
d4b96e3
build(deps): bump @nextcloud/axios from 2.5.2 to 2.6.0 (#762)
dependabot[bot] Sep 4, 2026
267888e
build(deps-dev): bump @typescript-eslint/parser from 8.68.0 to 8.69.0…
dependabot[bot] Sep 4, 2026
7664c0a
build(deps-dev): bump postcss-html from 1.8.1 to 2.0.0 (#760)
dependabot[bot] Sep 4, 2026
bb98156
feat(setup): ask which example data to load, as cards, instead of a b…
rubenvdlinde Sep 5, 2026
f1b9772
chore(release): 0.1.47-unstable.20260905095638 (#771)
rubenvdlinde Sep 5, 2026
0276ad2
Merge pull request #725 from ConductionNL/development
rubenvdlinde Sep 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,16 @@ updates:
update-types: ["version-update:semver-major"]
- dependency-name: "typescript"
update-types: ["version-update:semver-major"]
# vue-router 5 peers `vite: ^7.3.0 || ^8.0.0` and expects a Vite
# toolchain. Measured, not assumed, and the result is SPLIT: integriq and
# zaakafhandelapp fail their build on `Can't resolve 'vue-router'`, while
# openregister and learniq build clean on 5.3.0. Held because a bump that
# breaks some apps and not others cannot be merged unattended, and the
# difference is not yet understood. Adopting it fleet-wide is a
# Vite migration, not a bump. versioniq is already on Vite and is the
# natural pilot.
- dependency-name: "vue-router"
update-types: ["version-update:semver-major"]
cooldown:
default-days: 1
include:
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/code-quality.yml
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ permissions:

jobs:
quality:
if: (github.event_name != 'pull_request' || github.head_ref != 'development')
uses: ConductionNL/.github/.github/workflows/quality.yml@main
with:
app-name: hermiq
Expand Down
35 changes: 34 additions & 1 deletion appinfo/info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<description lang="nl"><![CDATA[Hermiq brengt autonome AI-agents naar Nextcloud. Definieer een agent, geef deze tools, en laat hem volgens een schema draaien — dagelijkse rapportages, inbox-triage, monitoring, ochtendbriefings — allemaal binnen je eigen Nextcloud, afgeleverd in Nextcloud Talk. Agents, hun geheugen en hun zelflerende skills worden opgeslagen als OpenRegister-objecten, zodat elke run beheerd, controleerbaar en multi-tenant is.

**Vereist:** [OpenRegister](https://apps.nextcloud.com/apps/openregister) 0.2.17-unstable.14 of hoger (installeer/upgrade via de [Nextcloud App Store](https://apps.nextcloud.com/apps/openregister)) — Hermiq's agent-engine (chat, geplande runs, flow-getriggerde agent-acties) roept OpenRegister's `ToolRegistryFacade` aan en luistert naar diens `AgentRunRequestedEvent`, die beide pas vanaf die OpenRegister-versie bestaan; de sectie "Agent-credentials" in Instellingen en de persoonlijke/organisatie-credentialresolutie hebben daarnaast OpenRegister's organisatiebrede credential broker nodig, die sinds diezelfde versie wordt geleverd.]]></description>
<version>0.1.40-unstable.20260830174612</version>
<version>0.1.47-unstable.20260905095638</version>
<licence>EUPL-1.2</licence>
<author mail="info@conduction.nl" homepage="https://www.conduction.nl/">Conduction</author>
<namespace>Hermiq</namespace>
Expand Down Expand Up @@ -132,6 +132,32 @@
silently reading null.
-->
<step>OCA\Hermiq\Repair\RenameDutchColumns</step>
<!-- @spec openspec/specs/flow-authoring/spec.md#requirement-a-flow-is-stored-once-by-openregister-req-fa-002 -->
<!-- Runs AFTER InitializeSettings: the v0.30.0 descriptor no longer
declares agentflow/agentflowrun, but the import unions schema ids
and never removes one, so this step deletes the retired schemas,
their rows and their tables. Idempotent: once pruned it finds
nothing and reports so. -->
<step>OCA\Hermiq\Repair\PruneRetiredAgentFlowSchemas</step>
<!-- @spec openspec/changes/approval-task-convergence/specs/approval-task-convergence/spec.md#requirement-in-flight-approvals-migrate-and-roll-back -->
<!-- Mirrors every already-pending Approval as an OpenRegister task
(approval-task convergence, phase 1). Post-migration only: a
fresh install has no approvals, and new ones are mirrored at
creation time by ApprovalService itself. Idempotent, guarded
on the stored taskUuid backlink; rollback is
`occ hermiq:approvals:rollback-task-mirror`. Runs after the
register sync so the schema's new taskUuid property exists. -->
<step>OCA\Hermiq\Repair\MirrorPendingApprovalsToTasks</step>
<!-- @spec openspec/changes/schedules-onto-engine-triggers/specs/schedule-engine-delegation/spec.md#requirement-in-flight-schedules-migrate-and-roll-back -->
<!-- Delegates every already-eligible schedule's clock to
OpenRegister's schedule trigger (schedules-onto-engine-triggers).
Post-migration only: new and edited schedules are armed by the
dispatch tick's own sync pass. Idempotent, guarded on the
stored engineFlowId marker; rollback is
`occ hermiq:schedules:rollback-flow-mirror`. Runs after the
register sync so the schema's new engineFlowId property
exists. -->
<step>OCA\Hermiq\Repair\MirrorSchedulesToEngineFlows</step>
</post-migration>
<install>
<step>OCA\Hermiq\Repair\CheckOpenRegisterCompatibility</step>
Expand Down Expand Up @@ -161,6 +187,13 @@
</install>
</repair-steps>

<commands>
<!-- @spec openspec/changes/approval-task-convergence/specs/approval-task-convergence/spec.md#requirement-in-flight-approvals-migrate-and-roll-back -->
<command>OCA\Hermiq\Command\RollbackApprovalTaskMirror</command>
<!-- @spec openspec/changes/schedules-onto-engine-triggers/specs/schedule-engine-delegation/spec.md#requirement-in-flight-schedules-migrate-and-roll-back -->
<command>OCA\Hermiq\Command\RollbackScheduleFlowMirror</command>
</commands>

<settings>
<admin>OCA\Hermiq\Settings\AdminSettings</admin>
<admin-section>OCA\Hermiq\Sections\SettingsSection</admin-section>
Expand Down
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@
"optimize-autoloader": true,
"sort-packages": true,
"platform": {
"php": "8.3"
"php": "8.3",
"ext-xsl": "1"
}
},
"extra": {
Expand Down
25 changes: 13 additions & 12 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

142 changes: 134 additions & 8 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -144,11 +144,32 @@ export default [
'no-console': 'off',
'n/no-process-exit': 'off',
'n/hashbang': 'off',
// `_` / `__` as a deliberate throwaway binding — `catch (_)`, a
// discarded destructuring slot. Narrow on purpose: the pattern matches
// UNDERSCORES ONLY, so a real name that happens to start with `_` is
// still reported. v9 drives plain `.js` through the CORE rule (the
// `@typescript-eslint` swap is per-file-type), so it is set here.
// Tests import devDependencies by definition; this rule is about what
// ships in the published package, which tests/ never does.
'n/no-unpublished-import': 'off',
},
},

{
// `_` / `__` as a deliberate throwaway binding — `catch (_)`, a discarded
// destructuring slot. Narrow on purpose: the pattern matches UNDERSCORES
// ONLY, so a real name that happens to start with `_` is still reported.
//
// 🔴 `.js` / `.mjs` ONLY, NOT `.ts`. The CORE rule is not TypeScript-aware:
// applied to a `.ts` file it reads the parameter NAMES inside a function
// TYPE as bindings and reports them unused. Measured on humaniq —
//
// t?: (app: string, key: string) => string
//
// produced four `no-unused-vars` errors for `app` and `key`, which are
// documentation, not variables. The same mis-scoping made every unused
// `catch (e)` in a `.ts` spec report TWICE, once per rule.
//
// v9 already turns the core rule off for `.ts` and drives
// `@typescript-eslint/no-unused-vars` instead; naming `.ts` here switched
// it back on. TypeScript files are handled by the block below.
files: ['tests/**/*.js', 'tests/**/*.mjs'],
rules: {
'no-unused-vars': [
'error',
{
Expand All @@ -165,12 +186,117 @@ export default [
ignoreRestSiblings: true,
},
],
// Tests import devDependencies by definition; this rule is about what
// ships in the published package, which tests/ never does.
'n/no-unpublished-import': 'off',
},
},

{
// The TypeScript half of the block above. Same intent, same patterns, on
// the rule that actually understands the language: it knows a name inside
// a function type is not a binding, so type annotations stay quiet while a
// genuinely dead local is still reported.
files: ['tests/**/*.ts', 'tests/**/*.tsx'],
rules: {
'@typescript-eslint/no-unused-vars': [
'error',
{
varsIgnorePattern: '^_+$',
caughtErrors: 'all',
caughtErrorsIgnorePattern: '^_+$',
argsIgnorePattern: '^_',
ignoreRestSiblings: true,
},
],
},
},

{
// 🔴 Node-side CLI tooling under `scripts/`, which is COMMONJS. Flat
// config defaults every `.js` to ESM with browser-ish globals, so without
// this block eslint reports the CommonJS wrapper itself as undefined
// identifiers. Measured on this app: 52 of the 233 errors under
// `tests/` + `scripts/` were `no-undef`, ALL of them in `scripts/`, and
// all five names were the environment rather than a typo — `process` 23,
// `require` 20, `__dirname` 6, `__filename` 2, `module` 1.
//
// This is describing the environment, not relaxing a rule, and it is the
// same argument the test-globals block below makes: declaring them keeps
// `no-undef` able to do its real job, which is catching a genuinely
// misspelled identifier. Suppressing the rule instead would bury that.
//
// `no-console` is off because printing its report is what a CLI checker
// is FOR.
//
// 🔴 NO `n/*` ENTRIES HERE, DELIBERATELY. `eslint-plugin-n` is NOT
// registered for these files under eslint 10 + @nextcloud/eslint-config
// 9, so `'n/no-process-exit': 'off'` would be dead config that reads as
// if it were doing something. Measured both ways on this app: 0 `n/`
// findings with the entries and 0 without.
//
// What DID report was the opposite — four `scripts/*.js` carried
// `/* eslint-disable n/no-process-exit */` and `/* eslint-disable
// n/shebang */` left over from the eslintrc era, and an inline disable
// naming an unregistered plugin is itself an error ("Definition for rule
// 'n/shebang' was not found"). Those 8 comments are removed; do not add
// `n/*` rules back to replace them.
//
// ⚠️ `.js` and `.cjs` ONLY. A `scripts/*.mjs` is genuinely ESM and must
// keep the default `sourceType`, or `import` stops parsing there.
files: ['scripts/**/*.js', 'scripts/**/*.cjs'],
languageOptions: {
sourceType: 'commonjs',
globals: {
require: 'readonly',
module: 'writable',
exports: 'writable',
process: 'readonly',
__dirname: 'readonly',
__filename: 'readonly',
console: 'readonly',
Buffer: 'readonly',
global: 'readonly',
URL: 'readonly',
TextEncoder: 'readonly',
TextDecoder: 'readonly',
},
},
rules: {
'no-console': 'off',
},
},

{
// The ESM half of the block above. A `scripts/*.mjs` is genuinely a module
// and must keep the default `sourceType`, so it gets Node's globals but
// none of the CommonJS wrapper. Measured: `process` reported undefined 2x
// in hermiq's generate-opengemeenten-icons.mjs and 4x in openregister's
// l10n/runtime-check.mjs, which the `.js`/`.cjs` block deliberately does
// not match.
files: ['scripts/**/*.mjs', 'tests/**/*.mjs'],
languageOptions: {
globals: {
process: 'readonly',
console: 'readonly',
Buffer: 'readonly',
global: 'readonly',
URL: 'readonly',
TextEncoder: 'readonly',
TextDecoder: 'readonly',
},
},
rules: {
'no-console': 'off',
},
},

{
// eslint must not try to PARSE a shell script. `tests/e2e/seed.test.sh`
// matches the `**/*.test.*` glob some presets use, and eslint then reads
// it as JavaScript and reports "Parsing error: Unexpected character" —
// a finding about a file it should never have opened.
ignores: ['**/*.sh', '**/*.bash'],
},


{
// Test globals. Several apps keep their spec files INSIDE `src/`, which the
// lint script scans, and neither `@nextcloud/eslint-config` nor the runner
Expand Down
13 changes: 12 additions & 1 deletion l10n/en.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
OC.L10N.register(
"hermiq",
{
"Load example data?": "Load example data?",
"Example data fills the lists, detail pages and dashboards so you can see the app working straight away. Pick \"None\" on a production install.": "Example data fills the lists, detail pages and dashboards so you can see the app working straight away. Pick \"None\" on a production install.",
"Load the example data": "Load the example data",
"Loads what you picked. The data is obviously sample data, it is safe to run more than once, and you can delete it afterwards.": "Loads what you picked. The data is obviously sample data, it is safe to run more than once, and you can delete it afterwards.",
"None, I will set this up myself": "None, I will set this up myself",
"Nothing is imported. You start with an empty app and add your own data.": "Nothing is imported. You start with an empty app and add your own data.",
"Example data": "Example data",
"Sample values for every schema this app supplies, generated from the schemas themselves. It shows the lists, detail pages and dashboards working rather than telling a story. Safe to run more than once, and you can delete it afterwards.": "Sample values for every schema this app supplies, generated from the schemas themselves. It shows the lists, detail pages and dashboards working rather than telling a story. Safe to run more than once, and you can delete it afterwards.",
"\"Satisfied\" means Hermiq can evidence this control from its own governance data — it is not a certification of compliance by a qualified auditor.": "\"Satisfied\" means Hermiq can evidence this control from its own governance data — it is not a certification of compliance by a qualified auditor.",
"%n case": "%n case",
"%n cases": "%n cases",
Expand Down Expand Up @@ -1307,7 +1315,10 @@ OC.L10N.register(
"Where this agent’s dictated audio is transcribed. “On this instance” never leaves the server and is slower; “browser” is instant and, in most browsers, sends the audio to the browser vendor.": "Where this agent’s dictated audio is transcribed. “On this instance” never leaves the server and is slower; “browser” is instant and, in most browsers, sends the audio to the browser vendor.",
"Where the automation lives": "Where the automation lives",
"Flows are what happens without anyone clicking: an agent that runs on a schedule, a hand-off that fires when a task completes. This is where you read and edit them. Nothing to build now.": "Flows are what happens without anyone clicking: an agent that runs on a schedule, a hand-off that fires when a task completes. This is where you read and edit them. Nothing to build now.",
"Open Flows in the menu": "Open Flows in the menu"
"Open Flows in the menu": "Open Flows in the menu",
"Reports": "Reports",
"Pick a report to open it.": "Pick a report to open it.",
"What the agents did, and what a human still has to answer for.": "What the agents did, and what a human still has to answer for."
},
"nplurals=2; plural=(n != 1);"
)
Loading
Loading