Skip to content

Commit 91814e1

Browse files
committed
WIP
1 parent 08e878c commit 91814e1

158 files changed

Lines changed: 30033 additions & 218 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude/settings.local.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,12 @@
1818
"Bash(done)",
1919
"Bash(/home/stachu/code/dark/scripts/build/build-release-cli-exes.sh:*)",
2020
"Bash(scripts/run-backend-tests:*)",
21-
"Bash(timeout:*)"
21+
"Bash(timeout:*)",
22+
"Read(//home/stachu/code/darklang.com/**)",
23+
"WebFetch(domain:code.visualstudio.com)",
24+
"Bash(pandoc:*)",
25+
"WebFetch(domain:lms.fargorate.com)",
26+
"WebSearch"
2227
],
2328
"deny": []
2429
}

2025-09-23-a-week-ago-i-had-collected-a-bunch-of-notes-about.txt

Lines changed: 1204 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
-- ===================================
2+
-- Package Management System Tables
3+
-- ===================================
4+
5+
-- Content storage (immutable, content-addressed)
6+
CREATE TABLE IF NOT EXISTS matter_content_v0 (
7+
hash TEXT PRIMARY KEY,
8+
content_type TEXT NOT NULL CHECK (content_type IN ('function', 'type', 'value')),
9+
content BLOB NOT NULL,
10+
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
11+
);
12+
13+
CREATE INDEX idx_matter_content_type ON matter_content_v0(content_type);
14+
15+
-- Name pointers (mutable pointers to content)
16+
CREATE TABLE IF NOT EXISTS matter_names_v0 (
17+
id UUID PRIMARY KEY DEFAULT (uuid()),
18+
owner TEXT NOT NULL,
19+
modules TEXT NOT NULL,
20+
name TEXT NOT NULL,
21+
hash TEXT NOT NULL REFERENCES matter_content_v0(hash),
22+
deprecated BOOLEAN NOT NULL DEFAULT FALSE,
23+
deprecation_reason TEXT,
24+
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
25+
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
26+
UNIQUE(owner, modules, name)
27+
);
28+
29+
CREATE INDEX idx_matter_names_location ON matter_names_v0(owner, modules, name);
30+
CREATE INDEX idx_matter_names_hash ON matter_names_v0(hash);
31+
32+
-- Instances
33+
CREATE TABLE IF NOT EXISTS matter_instances_v0 (
34+
id UUID PRIMARY KEY DEFAULT (uuid()),
35+
name TEXT NOT NULL UNIQUE,
36+
instance_type TEXT NOT NULL CHECK (instance_type IN ('LocalCLI', 'HttpServer')),
37+
last_sync_at TIMESTAMP,
38+
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
39+
);
40+
41+
-- Sessions
42+
CREATE TABLE IF NOT EXISTS matter_sessions_v0 (
43+
id UUID PRIMARY KEY DEFAULT (uuid()),
44+
name TEXT NOT NULL,
45+
intent TEXT NOT NULL,
46+
owner TEXT NOT NULL,
47+
current_patch_id UUID,
48+
state TEXT NOT NULL CHECK (state IN ('Active', 'Suspended', 'Completed')),
49+
workspace_state BLOB, -- Serialized workspace state
50+
started_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
51+
last_active_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
52+
);
53+
54+
CREATE INDEX idx_matter_sessions_owner ON matter_sessions_v0(owner);
55+
CREATE INDEX idx_matter_sessions_state ON matter_sessions_v0(state);
56+
57+
-- Patches
58+
CREATE TABLE IF NOT EXISTS matter_patches_v0 (
59+
id UUID PRIMARY KEY DEFAULT (uuid()),
60+
intent TEXT NOT NULL,
61+
author TEXT NOT NULL,
62+
status TEXT NOT NULL CHECK (status IN ('Draft', 'Ready', 'Applied', 'Rejected')),
63+
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
64+
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
65+
metadata BLOB -- Serialized patch metadata (todos, tags, etc)
66+
);
67+
68+
CREATE INDEX idx_matter_patches_author ON matter_patches_v0(author);
69+
CREATE INDEX idx_matter_patches_status ON matter_patches_v0(status);
70+
71+
-- Operations
72+
CREATE TABLE IF NOT EXISTS matter_ops_v0 (
73+
id UUID PRIMARY KEY DEFAULT (uuid()),
74+
patch_id UUID NOT NULL REFERENCES matter_patches_v0(id),
75+
sequence_num INTEGER NOT NULL,
76+
op_type TEXT NOT NULL,
77+
op_data BLOB NOT NULL, -- Serialized Op.T
78+
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
79+
UNIQUE(patch_id, sequence_num)
80+
);
81+
82+
CREATE INDEX idx_matter_ops_patch ON matter_ops_v0(patch_id);
83+
84+
-- Patch dependencies
85+
CREATE TABLE IF NOT EXISTS matter_patch_dependencies_v0 (
86+
patch_id UUID NOT NULL REFERENCES matter_patches_v0(id),
87+
depends_on_patch_id UUID NOT NULL REFERENCES matter_patches_v0(id),
88+
PRIMARY KEY (patch_id, depends_on_patch_id)
89+
);
90+
91+
-- Session patches (which patches belong to which session)
92+
CREATE TABLE IF NOT EXISTS matter_session_patches_v0 (
93+
session_id UUID NOT NULL REFERENCES matter_sessions_v0(id),
94+
patch_id UUID NOT NULL REFERENCES matter_patches_v0(id),
95+
added_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
96+
PRIMARY KEY (session_id, patch_id)
97+
);
98+
99+
CREATE INDEX idx_matter_session_patches_session ON matter_session_patches_v0(session_id);
100+
CREATE INDEX idx_matter_session_patches_patch ON matter_session_patches_v0(patch_id);

backend/src/LibExecution/ProgramTypes.fs

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -751,3 +751,161 @@ module Toplevel =
751751
match tl with
752752
| TLDB db -> db.tlid
753753
| TLHandler h -> h.tlid
754+
755+
756+
/// Represents a location in the package namespace
757+
module PackageLocation =
758+
type T = {
759+
owner: string
760+
modules: List<string>
761+
name: string
762+
}
763+
764+
let create (owner: string) (modules: List<string>) (name: string) : T =
765+
{ owner = owner; modules = modules; name = name }
766+
767+
let toString (location: T) : string =
768+
let moduleStr =
769+
if List.isEmpty location.modules then
770+
""
771+
else
772+
(String.concat "." location.modules) + "."
773+
$"{location.owner}.{moduleStr}{location.name}"
774+
775+
let parse (locationString: string) : Result<T, string> =
776+
let parts = locationString.Split('.') |> Array.toList
777+
match parts with
778+
| owner :: rest when not (List.isEmpty rest) ->
779+
let reversedRest = List.rev rest
780+
match reversedRest with
781+
| name :: reversedModules ->
782+
let modules = List.rev reversedModules
783+
Ok { owner = owner; modules = modules; name = name }
784+
| [] -> Error $"Invalid package location: {locationString}"
785+
| _ -> Error $"Invalid package location: {locationString}"
786+
787+
788+
/// Atomic operations that can be tracked and validated
789+
module Op =
790+
type T =
791+
// Content Operations - create new immutable content
792+
| AddFunctionContent of hash: string * content: PackageFn.PackageFn
793+
| AddTypeContent of hash: string * content: PackageType.PackageType
794+
| AddValueContent of hash: string * content: PackageValue.PackageValue
795+
796+
// Name Operations - manage name pointers
797+
| CreateName of location: PackageLocation.T * hash: string * contentType: string
798+
| UpdateNamePointer of location: PackageLocation.T * oldHash: string * newHash: string
799+
| MoveName of oldLocation: PackageLocation.T * newLocation: PackageLocation.T
800+
| UnassignName of location: PackageLocation.T
801+
802+
// Content Operations - deprecate content (by hash)
803+
| DeprecateContent of hash: string * reason: string * replacement: string option
804+
805+
806+
/// Patch status workflow
807+
module PatchStatus =
808+
type T =
809+
| Draft // Work in progress, can be modified
810+
| Ready // Complete and ready for review
811+
| Applied // Successfully applied to instance
812+
| Rejected // Rejected during validation
813+
814+
815+
/// A logical collection of operations
816+
module Patch =
817+
type Metadata = {
818+
todos: List<string>
819+
tags: List<string>
820+
testsCovered: List<string>
821+
}
822+
823+
type T = {
824+
id: uuid
825+
intent: string // Human-readable description
826+
ops: List<Op.T>
827+
parentPatches: List<uuid> // Patches this depends on
828+
status: PatchStatus.T
829+
author: string
830+
createdAt: System.DateTime
831+
updatedAt: System.DateTime
832+
metadata: Metadata
833+
}
834+
835+
836+
/// Session state
837+
module SessionState =
838+
type T =
839+
| Active
840+
| Suspended
841+
| Completed
842+
843+
844+
/// Working context within a session
845+
module WorkspaceState =
846+
type T = {
847+
openFiles: List<PackageLocation.T>
848+
currentFile: PackageLocation.T option
849+
breakpoints: List<PackageLocation.T * int>
850+
bookmarks: List<PackageLocation.T * string>
851+
}
852+
853+
let empty : T = {
854+
openFiles = []
855+
currentFile = None
856+
breakpoints = []
857+
bookmarks = []
858+
}
859+
860+
861+
/// A development session
862+
module Session =
863+
type T = {
864+
id: uuid
865+
name: string
866+
intent: string // What you're working on
867+
owner: string
868+
patches: List<uuid> // Patches created in this session
869+
currentPatch: uuid option
870+
startedAt: System.DateTime
871+
lastActiveAt: System.DateTime
872+
state: SessionState.T
873+
workspace: WorkspaceState.T
874+
}
875+
876+
877+
/// Instance types in the Darklang ecosystem
878+
module InstanceType =
879+
type T =
880+
| LocalCLI // Individual developer machine
881+
| HttpServer // Main Darklang package repository
882+
883+
884+
/// Darklang instance definition
885+
module Instance =
886+
type T = {
887+
id: uuid
888+
type_: InstanceType.T
889+
name: string
890+
lastSyncAt: System.DateTime option
891+
}
892+
893+
894+
/// Types of conflicts that can occur
895+
module Conflict =
896+
type T =
897+
// Two patches trying to point the same name to different content
898+
| NameConflict of location: PackageLocation.T * hash1: string * hash2: string
899+
// Type signature changed in incompatible way (to be defined more specifically later)
900+
| TypeIncompatibility of location: PackageLocation.T * oldHash: string * newHash: string
901+
902+
903+
/// Validation results for operations and patches
904+
module ValidationResult =
905+
type T = {
906+
isValid: bool
907+
conflicts: List<Conflict.T>
908+
dependencies: List<PackageLocation.T>
909+
warnings: List<string>
910+
suggestions: List<string>
911+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
module LibPackageManager.ContentStore
2+
3+
open System.Collections.Concurrent
4+
open Prelude
5+
open LibExecution.ProgramTypes
6+
7+
module PT = LibExecution.ProgramTypes
8+
9+
/// Content storage - immutable content addressed by hash
10+
type ContentType =
11+
| Function
12+
| Type
13+
| Value
14+
15+
type Content =
16+
| FunctionContent of PT.PackageFn.PackageFn
17+
| TypeContent of PT.PackageType.PackageType
18+
| ValueContent of PT.PackageValue.PackageValue
19+
20+
type DeprecationInfo = {
21+
reason: string
22+
replacement: string option
23+
}
24+
25+
// In-memory content cache
26+
let private contentCache = ConcurrentDictionary<string, Content>()
27+
28+
// In-memory deprecation tracking
29+
let private deprecationCache = ConcurrentDictionary<string, DeprecationInfo>()
30+
31+
let hashContent (content: Content) : string =
32+
// For now, simple hash implementation - in production use proper hashing
33+
match content with
34+
| FunctionContent fn -> $"fn-{fn.id}"
35+
| TypeContent t -> $"type-{t.id}"
36+
| ValueContent v -> $"val-{v.id}"
37+
38+
let addContent (hash: string) (content: Content) : unit =
39+
contentCache.TryAdd(hash, content) |> ignore<bool>
40+
41+
let getContent (hash: string) : Option<Content> =
42+
match contentCache.TryGetValue(hash) with
43+
| true, content -> Some content
44+
| false, _ -> None
45+
46+
let deprecateContent (hash: string) (reason: string) (replacement: string option) : unit =
47+
let info = { reason = reason; replacement = replacement }
48+
deprecationCache.AddOrUpdate(hash, info, fun _ _ -> info) |> ignore<DeprecationInfo>
49+
50+
let isDeprecated (hash: string) : Option<DeprecationInfo> =
51+
match deprecationCache.TryGetValue(hash) with
52+
| true, info -> Some info
53+
| false, _ -> None

backend/src/LibPackageManager/LibPackageManager.fsproj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,15 @@
2424
<Compile Include="Purge.fs" />
2525
<Compile Include="Inserts.fs" />
2626
<Compile Include="ProgramTypes.fs" />
27+
<Compile Include="ContentStore.fs" />
28+
<Compile Include="NameStore.fs" />
29+
<Compile Include="SessionProjection.fs" />
30+
<Compile Include="OpValidation.fs" />
31+
<Compile Include="OpExecution.fs" />
32+
<Compile Include="SessionStorage.fs" />
33+
<Compile Include="SessionManager.fs" />
2734
<Compile Include="RuntimeTypes.fs" />
35+
<Compile Include="SessionAwarePackageManager.fs" />
2836
<Compile Include="PackageManager.fs" />
2937
<Compile Include="Scripts.fs" />
3038
</ItemGroup>
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
module LibPackageManager.NameStore
2+
3+
open System.Collections.Concurrent
4+
open Prelude
5+
open LibExecution.ProgramTypes
6+
7+
module PT = LibExecution.ProgramTypes
8+
9+
/// Name resolution - maps package locations to content hashes
10+
type NameEntry = {
11+
location: PT.PackageLocation.T
12+
hash: string
13+
contentType: ContentStore.ContentType
14+
}
15+
16+
// In-memory name mappings
17+
let private nameStore = ConcurrentDictionary<string, NameEntry>()
18+
19+
let private locationKey (location: PT.PackageLocation.T) : string =
20+
PT.PackageLocation.toString location
21+
22+
let setName (location: PT.PackageLocation.T) (hash: string) (contentType: ContentStore.ContentType) : unit =
23+
let entry = {
24+
location = location
25+
hash = hash
26+
contentType = contentType
27+
}
28+
nameStore.AddOrUpdate(locationKey location, entry, fun _ _ -> entry) |> ignore<NameEntry>
29+
30+
let getName (location: PT.PackageLocation.T) : Option<NameEntry> =
31+
match nameStore.TryGetValue(locationKey location) with
32+
| true, entry -> Some entry
33+
| false, _ -> None
34+
35+
let deleteName (location: PT.PackageLocation.T) : bool =
36+
let key = locationKey location
37+
nameStore.TryRemove(key) |> fst

0 commit comments

Comments
 (0)