feat: Phase 1 — extract the client (web SPA + desktop) to dtoro/oikos-web
Some checks failed
ci / build-test (push) Has been cancelled
ci / docker-build (push) Has been cancelled

Problem: the hexagonal refactor churns the backend tree for nine more
phases; the UI delivery stack (web/ SPA, cmd/desktop Wails wrapper,
compose/web image) must move to its own repo first so doc/layout
rewrites land once on a backend-only tree.

Change:
- New repo git.hubris.network/dtoro/oikos-web (v0.33.0): web/, desktop/
  (updateURL repointed to oikos-web releases), compose/, own CI (web +
  desktop jobs), own deploy script (CI-green gate, TOCTOU guard,
  version-tagged images, prune-to-3), own webhook receiver on :9798 +
  launchd unit, own compose project publishing the same 8091:80.
- Cutover executed on mac-mini in order: oikos stack's web service
  stopped+removed, oikos-web project brought up on 8091; outer Caddy
  untouched (targets the published port) — serving + Authentik flow +
  /wails 404 quirk verified post-cutover.
- Stripped from oikos: web/, cmd/desktop/, compose/web/, desktop CI
  workflow, ci.yml web job, Makefile ui/desktop/desktop-package/install
  targets, the compose web service, oikos-web from deploy.sh's fallback
  prune list; wails + go-keyring dropped from go.mod, vendor synced.
- README / CONTRIBUTING / AGENTS.md / .agents dev+operations docs now
  point at the new repo; mbse + mascot design docs carry a path note.

Risk: production SPA serving depends on the new pipeline now; rollback
is versioned-image re-up of the old web service from a pre-split
checkout (port 8091). Desktop builds installed before the split still
check dtoro/oikos releases — one manual reinstall, noted in the
oikos-web release notes.

Verification: go vet, make test (race), make generate-check, golangci
(no new findings; baseline down 400→365); post-cutover curls —
localhost:8091 200, /wails/runtime.js 404, outer Caddy 302 Authentik.
This commit is contained in:
2026-08-15 22:27:52 +02:00
parent e074f04bdf
commit d4d99a7473
18854 changed files with 2615729 additions and 173735 deletions

View File

@@ -0,0 +1,3 @@
import type { Linter } from 'eslint';
declare const config: Linter.LegacyConfig;
export = config;

View File

@@ -0,0 +1,18 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
const node_path_1 = __importDefault(require("node:path"));
const rules_1 = require("../utils/rules");
const base = require.resolve('./base');
const baseExtend = node_path_1.default.extname(`${base}`) === '.ts' ? 'plugin:svelte/base' : base;
const config = {
extends: [baseExtend],
rules: Object.fromEntries(rules_1.rules
.map((rule) => [`svelte/${rule.meta.docs.ruleName}`, 'error'])
.filter(([ruleName]) => ![
// Does not work without options.
'svelte/no-restricted-html-elements'
].includes(ruleName)))
};
module.exports = config;

View File

@@ -0,0 +1,3 @@
import type { Linter } from 'eslint';
declare const config: Linter.LegacyConfig;
export = config;

View File

@@ -0,0 +1,21 @@
"use strict";
const config = {
plugins: ['svelte'],
overrides: [
{
files: ['*.svelte'],
parser: require.resolve('svelte-eslint-parser'),
rules: {
// ESLint core rules known to cause problems with `.svelte`.
'no-inner-declarations': 'off', // The AST generated by svelte-eslint-parser will false positives in it rule because the root node of the script is not the `Program`.
// "no-irregular-whitespace": "off",
// Self assign is one of way to update reactive value in Svelte.
'no-self-assign': 'off',
// eslint-plugin-svelte rules
'svelte/comment-directive': 'error',
'svelte/system': 'error'
}
}
]
};
module.exports = config;

View File

@@ -0,0 +1,3 @@
import type { Linter } from 'eslint';
declare const config: Linter.Config[];
export default config;

View File

@@ -0,0 +1,20 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const rules_1 = require("../../utils/rules");
const base_1 = __importDefault(require("./base"));
const config = [
...base_1.default,
{
name: 'svelte:all:rules',
rules: Object.fromEntries(rules_1.rules
.map((rule) => [`svelte/${rule.meta.docs.ruleName}`, 'error'])
.filter(([ruleName]) => ![
// Does not work without options.
'svelte/no-restricted-html-elements'
].includes(ruleName)))
}
];
exports.default = config;

View File

@@ -0,0 +1,3 @@
import type { Linter } from 'eslint';
declare const config: Linter.Config[];
export default config;

View File

@@ -0,0 +1,33 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const config = [
{
name: 'svelte:base:setup-plugin',
plugins: {
get svelte() {
// eslint-disable-next-line @typescript-eslint/no-require-imports -- ignore
return require('../../index');
}
}
},
{
name: 'svelte:base:setup-for-svelte',
files: ['*.svelte', '**/*.svelte'],
languageOptions: {
// eslint-disable-next-line @typescript-eslint/no-require-imports -- ignore
parser: require('svelte-eslint-parser')
},
rules: {
// ESLint core rules known to cause problems with `.svelte`.
'no-inner-declarations': 'off', // The AST generated by svelte-eslint-parser will false positives in it rule because the root node of the script is not the `Program`.
// "no-irregular-whitespace": "off",
// Self assign is one of way to update reactive value in Svelte.
'no-self-assign': 'off',
// eslint-plugin-svelte rules
'svelte/comment-directive': 'error',
'svelte/system': 'error'
},
processor: 'svelte/svelte'
}
];
exports.default = config;

View File

@@ -0,0 +1,3 @@
import type { Linter } from 'eslint';
declare const config: Linter.Config[];
export default config;

View File

@@ -0,0 +1,28 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const base_1 = __importDefault(require("./base"));
const config = [
...base_1.default,
{
name: 'svelte:prettier:turn-off-rules',
rules: {
// eslint-plugin-svelte rules
'svelte/first-attribute-linebreak': 'off',
'svelte/html-closing-bracket-new-line': 'off',
'svelte/html-closing-bracket-spacing': 'off',
'svelte/html-quotes': 'off',
'svelte/html-self-closing': 'off',
'svelte/indent': 'off',
'svelte/max-attributes-per-line': 'off',
'svelte/mustache-spacing': 'off',
'svelte/no-spaces-around-equal-signs-in-attribute': 'off',
'svelte/no-trailing-spaces': 'off',
'svelte/shorthand-attribute': 'off',
'svelte/shorthand-directive': 'off'
}
}
];
exports.default = config;

View File

@@ -0,0 +1,3 @@
import type { Linter } from 'eslint';
declare const config: Linter.Config[];
export default config;

View File

@@ -0,0 +1,30 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const base_1 = __importDefault(require("./base"));
const config = [
...base_1.default,
{
name: 'svelte:recommended:rules',
rules: {
// eslint-plugin-svelte rules
'svelte/comment-directive': 'error',
'svelte/no-at-debug-tags': 'warn',
'svelte/no-at-html-tags': 'error',
'svelte/no-dupe-else-if-blocks': 'error',
'svelte/no-dupe-style-properties': 'error',
'svelte/no-dynamic-slot-name': 'error',
'svelte/no-inner-declarations': 'error',
'svelte/no-not-function-handler': 'error',
'svelte/no-object-in-text-mustaches': 'error',
'svelte/no-shorthand-style-property-overrides': 'error',
'svelte/no-unknown-style-directive-property': 'error',
'svelte/no-unused-svelte-ignore': 'error',
'svelte/system': 'error',
'svelte/valid-compile': 'error'
}
}
];
exports.default = config;

View File

@@ -0,0 +1,3 @@
import type { Linter } from 'eslint';
declare const config: Linter.LegacyConfig;
export = config;

View File

@@ -0,0 +1,26 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
const node_path_1 = __importDefault(require("node:path"));
const base = require.resolve('./base');
const baseExtend = node_path_1.default.extname(`${base}`) === '.ts' ? 'plugin:svelte/base' : base;
const config = {
extends: [baseExtend],
rules: {
// eslint-plugin-svelte rules
'svelte/first-attribute-linebreak': 'off',
'svelte/html-closing-bracket-new-line': 'off',
'svelte/html-closing-bracket-spacing': 'off',
'svelte/html-quotes': 'off',
'svelte/html-self-closing': 'off',
'svelte/indent': 'off',
'svelte/max-attributes-per-line': 'off',
'svelte/mustache-spacing': 'off',
'svelte/no-spaces-around-equal-signs-in-attribute': 'off',
'svelte/no-trailing-spaces': 'off',
'svelte/shorthand-attribute': 'off',
'svelte/shorthand-directive': 'off'
}
};
module.exports = config;

View File

@@ -0,0 +1,3 @@
import type { Linter } from 'eslint';
declare const config: Linter.LegacyConfig;
export = config;

View File

@@ -0,0 +1,28 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
const node_path_1 = __importDefault(require("node:path"));
const base = require.resolve('./base');
const baseExtend = node_path_1.default.extname(`${base}`) === '.ts' ? 'plugin:svelte/base' : base;
const config = {
extends: [baseExtend],
rules: {
// eslint-plugin-svelte rules
'svelte/comment-directive': 'error',
'svelte/no-at-debug-tags': 'warn',
'svelte/no-at-html-tags': 'error',
'svelte/no-dupe-else-if-blocks': 'error',
'svelte/no-dupe-style-properties': 'error',
'svelte/no-dynamic-slot-name': 'error',
'svelte/no-inner-declarations': 'error',
'svelte/no-not-function-handler': 'error',
'svelte/no-object-in-text-mustaches': 'error',
'svelte/no-shorthand-style-property-overrides': 'error',
'svelte/no-unknown-style-directive-property': 'error',
'svelte/no-unused-svelte-ignore': 'error',
'svelte/system': 'error',
'svelte/valid-compile': 'error'
}
};
module.exports = config;