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

173
web/node_modules/eslint/lib/rules/no-redeclare.js generated vendored Normal file
View File

@@ -0,0 +1,173 @@
/**
* @fileoverview Rule to flag when the same variable is declared more then once.
* @author Ilya Volodin
*/
"use strict";
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
const astUtils = require("./utils/ast-utils");
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
/** @type {import('../types').Rule.RuleModule} */
module.exports = {
meta: {
type: "suggestion",
defaultOptions: [{ builtinGlobals: true }],
docs: {
description: "Disallow variable redeclaration",
recommended: true,
url: "https://eslint.org/docs/latest/rules/no-redeclare",
},
messages: {
redeclared: "'{{id}}' is already defined.",
redeclaredAsBuiltin:
"'{{id}}' is already defined as a built-in global variable.",
redeclaredBySyntax:
"'{{id}}' is already defined by a variable declaration.",
},
schema: [
{
type: "object",
properties: {
builtinGlobals: { type: "boolean" },
},
additionalProperties: false,
},
],
},
create(context) {
const [{ builtinGlobals }] = context.options;
const sourceCode = context.sourceCode;
/**
* Iterate declarations of a given variable.
* @param {escope.variable} variable The variable object to iterate declarations.
* @returns {IterableIterator<{type:string,node:ASTNode,loc:SourceLocation}>} The declarations.
*/
function* iterateDeclarations(variable) {
if (
builtinGlobals &&
(variable.eslintImplicitGlobalSetting === "readonly" ||
variable.eslintImplicitGlobalSetting === "writable")
) {
yield { type: "builtin" };
}
for (const id of variable.identifiers) {
yield { type: "syntax", node: id, loc: id.loc };
}
if (variable.eslintExplicitGlobalComments) {
for (const comment of variable.eslintExplicitGlobalComments) {
yield {
type: "comment",
node: comment,
loc: astUtils.getNameLocationInGlobalDirectiveComment(
sourceCode,
comment,
variable.name,
),
};
}
}
}
/**
* Find variables in a given scope and flag redeclared ones.
* @param {Scope} scope An eslint-scope scope object.
* @returns {void}
* @private
*/
function findVariablesInScope(scope) {
for (const variable of scope.variables) {
const [declaration, ...extraDeclarations] =
iterateDeclarations(variable);
if (extraDeclarations.length === 0) {
continue;
}
/*
* If the type of a declaration is different from the type of
* the first declaration, it shows the location of the first
* declaration.
*/
const detailMessageId =
declaration.type === "builtin"
? "redeclaredAsBuiltin"
: "redeclaredBySyntax";
const data = { id: variable.name };
// Report extra declarations.
for (const { type, node, loc } of extraDeclarations) {
const messageId =
type === declaration.type
? "redeclared"
: detailMessageId;
context.report({ node, loc, messageId, data });
}
}
}
/**
* Find variables in the current scope.
* @param {ASTNode} node The node of the current scope.
* @returns {void}
* @private
*/
function checkForBlock(node) {
const scope = sourceCode.getScope(node);
/*
* In ES5, some node type such as `BlockStatement` doesn't have that scope.
* `scope.block` is a different node in such a case.
*/
if (scope.block === node) {
findVariablesInScope(scope);
}
}
return {
Program(node) {
const scope = sourceCode.getScope(node);
findVariablesInScope(scope);
// Node.js or ES modules has a special scope.
if (
scope.type === "global" &&
scope.childScopes[0] &&
// The special scope's block is the Program node.
scope.block === scope.childScopes[0].block
) {
findVariablesInScope(scope.childScopes[0]);
}
},
FunctionDeclaration: checkForBlock,
FunctionExpression: checkForBlock,
ArrowFunctionExpression: checkForBlock,
StaticBlock: checkForBlock,
BlockStatement: checkForBlock,
ForStatement: checkForBlock,
ForInStatement: checkForBlock,
ForOfStatement: checkForBlock,
SwitchStatement: checkForBlock,
};
},
};