Ablage je Einheit, Stufe 1: benannte Arbeitsbereiche mit Mitgliedern (#684)

- WorkspaceConfig in der Instanzkonfiguration: Id, Name, Zweck,
  Eigentuemer-Einheit, Mitglieder (Einheit oder Agent, Stufe Read/Write/
  Manage, Untereinheiten ein/aus), geschuetzte Pfade. Das Recht steht am
  Bereich, nicht am Agenten.
- OrgChart: AccessTo, WorkspacesFor, UnitWorkspace; Problems nennt
  ungueltige Ids und tote Verweise. WorkspaceLayout: Bereiche liegen unter
  Agents/SharedWorkspaces/<id>/, neben dem unveraenderten SharedWorkspace.
- FileRW: workspace ist ein Name - personal, shared (wie bisher ueber
  sharedAccessLevel), unit (eigene Einheit) oder eine Bereichs-Id. Ein
  unbekannter und ein nicht erlaubter Bereich bekommen dieselbe Antwort.
  Loeschen braucht Manage wie frueher Admin. Der #662-Hinweis sucht in allen
  erlaubten Bereichen.
- Mit Einheiten ist shared:/tasks/ fuer FileRW gesperrt: Aufgaben laufen
  ueber das Brett, sonst umginge eine direkt geschriebene Datei Brett- und
  Adressbuchpruefung. Ohne Einheiten unveraendert.
- Organisationsabschnitt im Prompt nennt die Bereiche mit Stufe und Zweck.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Richard
2026-09-24 16:52:03 +02:00
co-authored by Claude Opus 5.5
parent ba5fe4cdf7
commit ff20ce2563
8 changed files with 901 additions and 139 deletions
@@ -179,6 +179,14 @@ public sealed class InstanceConfig
[JsonPropertyName("units")]
public List<UnitConfig> Units { get; set; } = new();
/// <summary>
/// #684: Shared workspaces with member lists — one per unit, plus those shared across
/// units on purpose. The instance's one shared folder is not listed here; it stays the
/// workspace <c>shared</c>, governed by each agent's level as before.
/// </summary>
[JsonPropertyName("workspaces")]
public List<WorkspaceConfig> Workspaces { get; set; } = new();
[JsonPropertyName("services")]
public List<ServiceConfig> Services { get; set; } = new();
}
@@ -0,0 +1,85 @@
using System.Text.Json.Serialization;
namespace ClawdDotNet.Core.Config;
/// <summary>
/// #684: A shared workspace — a folder several agents work in, with a named owner and a list
/// of who may use it how.
///
/// <para><b>The right stands at the workspace, not at the agent</b> (Organisation-Konzept,
/// section 3). Before, every agent carried one <c>sharedAccessLevel</c> for the one shared
/// folder of the instance, and "accounting may write its files, marketing may only read
/// them" could not be said. Here each workspace lists its members; whoever is not on the
/// list does not see it — not even that it exists.</para>
///
/// <para><b>The one shared folder stays what it was.</b> The folder <c>SharedWorkspace</c>
/// with the per-agent level keeps working as the workspace <c>shared</c>, so every running
/// installation and every task that names it goes on as before. Workspaces configured here
/// live next to it, under <c>SharedWorkspaces/&lt;id&gt;/</c>. There is never a second
/// value for the same thing: <c>shared</c> is governed only by the agent's level, every
/// workspace here only by its member list.</para>
/// </summary>
public sealed class WorkspaceConfig
{
/// <summary>The name agents use and the folder name; lower case, digits and dashes.</summary>
[JsonPropertyName("id")]
public string Id { get; set; } = "";
[JsonPropertyName("name")]
public string Name { get; set; } = "";
/// <summary>What goes in here — shown to the members so they file things in the right place.</summary>
[JsonPropertyName("purpose")]
public string Purpose { get; set; } = "";
/// <summary>
/// The unit the workspace belongs to — what is filed here is its property, and stays
/// when an agent moves on. <c>null</c>: owned by the instance (the human).
/// </summary>
[JsonPropertyName("ownerUnitId")]
public string? OwnerUnitId { get; set; }
[JsonPropertyName("members")]
public List<WorkspaceMember> Members { get; set; } = new();
/// <summary>
/// Folders in which files can only be added, not changed or deleted — except by members
/// with <see cref="WorkspaceAccess.Manage"/>. Relative to the workspace.
/// </summary>
[JsonPropertyName("protectedPaths")]
public List<string> ProtectedPaths { get; set; } = new();
}
/// <summary>
/// #684: One entry on a workspace's member list — a unit or a single agent, with a level.
/// A unit entry includes the units below it unless <see cref="IncludeSubUnits"/> is off;
/// a unit's own workspace is meant for the whole department.
/// </summary>
public sealed class WorkspaceMember
{
[JsonPropertyName("unitId")]
public string? UnitId { get; set; }
[JsonPropertyName("agentId")]
public string? AgentId { get; set; }
[JsonPropertyName("access")]
public WorkspaceAccess Access { get; set; } = WorkspaceAccess.Read;
[JsonPropertyName("includeSubUnits")]
public bool IncludeSubUnits { get; set; } = true;
}
/// <summary>
/// #684: What a member may do in a workspace. Each level includes the ones below it.
/// Deleting and changing protected files needs <see cref="Manage"/> — as the old
/// <c>Admin</c> level did for the one shared folder.
/// </summary>
[JsonConverter(typeof(JsonStringEnumConverter<WorkspaceAccess>))]
public enum WorkspaceAccess
{
None = 0,
Read = 1,
Write = 2,
Manage = 3
}