@wipcomputer/wip-ldm-os 0.4.73-alpha.3 → 0.4.73-alpha.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +52 -0
- package/bin/ldm.js +512 -95
- package/dist/bridge/chunk-3RG5ZIWI.js +10 -0
- package/dist/bridge/{chunk-LF7EMFBY.js → chunk-7NH6JBIO.js} +127 -49
- package/dist/bridge/cli.js +2 -1
- package/dist/bridge/core.d.ts +13 -1
- package/dist/bridge/core.js +4 -1
- package/dist/bridge/mcp-server.js +52 -7
- package/dist/bridge/openclaw.d.ts +5 -0
- package/dist/bridge/openclaw.js +11 -0
- package/docs/doc-pipeline/README.md +74 -0
- package/docs/doc-pipeline/TECHNICAL.md +79 -0
- package/lib/deploy.mjs +94 -10
- package/lib/detect.mjs +20 -6
- package/package.json +2 -2
- package/shared/docs/README.md.tmpl +2 -2
- package/shared/docs/how-install-works.md.tmpl +22 -2
- package/shared/docs/how-releases-work.md.tmpl +58 -42
- package/shared/docs/how-worktrees-work.md.tmpl +12 -7
- package/shared/rules/git-conventions.md +3 -3
- package/shared/rules/release-pipeline.md +1 -1
- package/shared/rules/security.md +1 -1
- package/shared/rules/workspace-boundaries.md +1 -1
- package/shared/rules/writing-style.md +1 -1
- package/shared/templates/claude-md-level1.md +7 -3
- package/src/bridge/core.ts +160 -56
- package/src/bridge/mcp-server.ts +93 -8
- package/src/bridge/openclaw.ts +14 -0
- package/src/hooks/inbox-check-hook.mjs +194 -0
- package/src/hooks/inbox-rewake-hook.mjs +338 -0
- package/src/hosted-mcp/.env.example +3 -0
- package/src/hosted-mcp/demo/agent.html +300 -0
- package/src/hosted-mcp/demo/agent.txt +84 -0
- package/src/hosted-mcp/demo/fallback.jpg +0 -0
- package/src/hosted-mcp/demo/footer.js +74 -0
- package/src/hosted-mcp/demo/index.html +1303 -0
- package/src/hosted-mcp/demo/login.html +548 -0
- package/src/hosted-mcp/demo/privacy.html +223 -0
- package/src/hosted-mcp/demo/sprites.jpg +0 -0
- package/src/hosted-mcp/demo/sprites.png +0 -0
- package/src/hosted-mcp/demo/tos.html +198 -0
- package/src/hosted-mcp/deploy.sh +70 -0
- package/src/hosted-mcp/ecosystem.config.cjs +14 -0
- package/src/hosted-mcp/inbox.mjs +64 -0
- package/src/hosted-mcp/legal/internet-services/terms/site.html +205 -0
- package/src/hosted-mcp/legal/privacy/en-ww/index.html +230 -0
- package/src/hosted-mcp/nginx/mcp-oauth.conf +98 -0
- package/src/hosted-mcp/nginx/mcp-server.conf +17 -0
- package/src/hosted-mcp/nginx/wip.computer.conf +45 -0
- package/src/hosted-mcp/package-lock.json +2092 -0
- package/src/hosted-mcp/package.json +23 -0
- package/src/hosted-mcp/prisma/migrations/20260406233014_init/migration.sql +68 -0
- package/src/hosted-mcp/prisma/migrations/migration_lock.toml +3 -0
- package/src/hosted-mcp/prisma/schema.prisma +57 -0
- package/src/hosted-mcp/prisma.config.ts +14 -0
- package/src/hosted-mcp/server.mjs +2079 -0
- package/src/hosted-mcp/tools.mjs +73 -0
- package/templates/hooks/pre-commit +5 -0
package/lib/deploy.mjs
CHANGED
|
@@ -394,14 +394,38 @@ function runBuildIfNeeded(repoPath) {
|
|
|
394
394
|
|
|
395
395
|
function compareSemver(a, b) {
|
|
396
396
|
if (!a || !b) return 0;
|
|
397
|
-
|
|
398
|
-
const
|
|
397
|
+
if (a === b) return 0;
|
|
398
|
+
const [aBase, aPre] = a.split('-', 2);
|
|
399
|
+
const [bBase, bPre] = b.split('-', 2);
|
|
400
|
+
const pa = aBase.split('.').map(Number);
|
|
401
|
+
const pb = bBase.split('.').map(Number);
|
|
399
402
|
for (let i = 0; i < 3; i++) {
|
|
400
403
|
const na = pa[i] || 0;
|
|
401
404
|
const nb = pb[i] || 0;
|
|
402
405
|
if (na > nb) return 1;
|
|
403
406
|
if (na < nb) return -1;
|
|
404
407
|
}
|
|
408
|
+
// Base versions equal. Stable > prerelease.
|
|
409
|
+
if (!aPre && bPre) return 1; // a is stable, b is prerelease -> a is newer
|
|
410
|
+
if (aPre && !bPre) return -1; // a is prerelease, b is stable -> b is newer
|
|
411
|
+
// Both have prereleases. Compare segments.
|
|
412
|
+
if (aPre && bPre) {
|
|
413
|
+
const aSegs = aPre.split('.');
|
|
414
|
+
const bSegs = bPre.split('.');
|
|
415
|
+
for (let i = 0; i < Math.max(aSegs.length, bSegs.length); i++) {
|
|
416
|
+
const as = aSegs[i] || '';
|
|
417
|
+
const bs = bSegs[i] || '';
|
|
418
|
+
const an = Number(as);
|
|
419
|
+
const bn = Number(bs);
|
|
420
|
+
if (!isNaN(an) && !isNaN(bn)) {
|
|
421
|
+
if (an > bn) return 1;
|
|
422
|
+
if (an < bn) return -1;
|
|
423
|
+
} else {
|
|
424
|
+
if (as > bs) return 1;
|
|
425
|
+
if (as < bs) return -1;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
}
|
|
405
429
|
return 0;
|
|
406
430
|
}
|
|
407
431
|
|
|
@@ -508,6 +532,32 @@ function safeDeployDir(repoPath, destDir, name) {
|
|
|
508
532
|
}
|
|
509
533
|
}
|
|
510
534
|
|
|
535
|
+
/**
|
|
536
|
+
* Update tools.allow in openclaw.json to include a newly deployed plugin.
|
|
537
|
+
* OpenClaw 2026.4.8+ enforces tools.allow as an exclusive allowlist.
|
|
538
|
+
* Without this, newly installed plugins are blocked from running.
|
|
539
|
+
*
|
|
540
|
+
* This function MUST remain at module top level. Nesting it inside another
|
|
541
|
+
* function puts it out of scope for its call sites in the install handlers
|
|
542
|
+
* and produces a ReferenceError at runtime. See:
|
|
543
|
+
* ai/product/bugs/installer/2026-04-11--cc-mini--update-tools-allow-reference-error.md
|
|
544
|
+
*/
|
|
545
|
+
function updateToolsAllow(pluginName) {
|
|
546
|
+
const ocConfigPath = join(OC_ROOT, 'openclaw.json');
|
|
547
|
+
if (!existsSync(ocConfigPath)) return;
|
|
548
|
+
try {
|
|
549
|
+
const raw = readFileSync(ocConfigPath, 'utf8');
|
|
550
|
+
const config = JSON.parse(raw);
|
|
551
|
+
if (!config.tools?.allow || !Array.isArray(config.tools.allow)) return;
|
|
552
|
+
if (config.tools.allow.includes(pluginName)) return;
|
|
553
|
+
config.tools.allow.push(pluginName);
|
|
554
|
+
writeFileSync(ocConfigPath, JSON.stringify(config, null, 2) + '\n');
|
|
555
|
+
log(`Added "${pluginName}" to openclaw.json tools.allow`);
|
|
556
|
+
} catch (e) {
|
|
557
|
+
log(`Warning: failed to update tools.allow for ${pluginName}: ${e.message}`);
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
|
|
511
561
|
// ── OpenClaw plugin naming (fix #8) ──
|
|
512
562
|
|
|
513
563
|
function resolveOcPluginName(repoPath, toolName) {
|
|
@@ -788,7 +838,28 @@ function registerMCP(repoPath, door, toolName) {
|
|
|
788
838
|
}
|
|
789
839
|
}
|
|
790
840
|
|
|
791
|
-
|
|
841
|
+
/**
|
|
842
|
+
* Install Claude Code hook(s) for an extension.
|
|
843
|
+
*
|
|
844
|
+
* Accepts either a single door object (legacy) or an array of door objects
|
|
845
|
+
* (new in 2026-04-05 for wip-branch-guard 1.9.73 which registers on both
|
|
846
|
+
* PreToolUse and SessionStart). Normalizes to an array and installs each
|
|
847
|
+
* door independently.
|
|
848
|
+
*
|
|
849
|
+
* Returns true if at least one door installed successfully.
|
|
850
|
+
*/
|
|
851
|
+
function installClaudeCodeHook(repoPath, doorOrDoors) {
|
|
852
|
+
const doors = Array.isArray(doorOrDoors) ? doorOrDoors : [doorOrDoors];
|
|
853
|
+
let anyOk = false;
|
|
854
|
+
for (const door of doors) {
|
|
855
|
+
if (installClaudeCodeHookEvent(repoPath, door)) {
|
|
856
|
+
anyOk = true;
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
return anyOk;
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
function installClaudeCodeHookEvent(repoPath, door) {
|
|
792
863
|
const settingsPath = join(HOME, '.claude', 'settings.json');
|
|
793
864
|
let settings = readJSON(settingsPath);
|
|
794
865
|
|
|
@@ -802,6 +873,8 @@ function installClaudeCodeHook(repoPath, door) {
|
|
|
802
873
|
const installedGuard = join(extDir, 'guard.mjs');
|
|
803
874
|
|
|
804
875
|
// Deploy guard.mjs to ~/.ldm/extensions/{toolName}/ (#85: always update, not just when missing)
|
|
876
|
+
// Idempotent across multi-door invocations: two doors on the same repo
|
|
877
|
+
// will both trigger this copy, which is a filesystem no-op after the first.
|
|
805
878
|
const srcGuard = join(repoPath, 'guard.mjs');
|
|
806
879
|
if (existsSync(srcGuard)) {
|
|
807
880
|
try {
|
|
@@ -819,21 +892,30 @@ function installClaudeCodeHook(repoPath, door) {
|
|
|
819
892
|
? `node ${installedGuard}`
|
|
820
893
|
: (door.command || `node "${srcGuard}"`);
|
|
821
894
|
|
|
895
|
+
const event = door.event || 'PreToolUse';
|
|
896
|
+
|
|
822
897
|
if (DRY_RUN) {
|
|
823
|
-
ok(`Claude Code: would add ${
|
|
898
|
+
ok(`Claude Code: would add ${event} hook (dry run)`);
|
|
824
899
|
return true;
|
|
825
900
|
}
|
|
826
901
|
|
|
827
902
|
if (!settings.hooks) settings.hooks = {};
|
|
828
|
-
const event = door.event || 'PreToolUse';
|
|
829
903
|
if (!settings.hooks[event]) settings.hooks[event] = [];
|
|
830
904
|
|
|
831
|
-
|
|
832
|
-
|
|
905
|
+
// Match existing entries by the guard command path + the matcher, so that
|
|
906
|
+
// a single extension registering on multiple events (each with its own
|
|
907
|
+
// matcher) creates one entry per event rather than all entries colliding
|
|
908
|
+
// on the same hook slot. Before this change the existing-entry check was
|
|
909
|
+
// per-extension, not per-extension-per-event.
|
|
910
|
+
const doorMatcher = door.matcher || undefined;
|
|
911
|
+
const existingIdx = settings.hooks[event].findIndex(entry => {
|
|
912
|
+
const sameMatcher = (entry.matcher || undefined) === doorMatcher;
|
|
913
|
+
if (!sameMatcher) return false;
|
|
914
|
+
return entry.hooks?.some(h => {
|
|
833
915
|
const cmd = h.command || '';
|
|
834
916
|
return cmd.includes(`/${toolName}/`) || cmd === hookCommand;
|
|
835
|
-
})
|
|
836
|
-
);
|
|
917
|
+
});
|
|
918
|
+
});
|
|
837
919
|
|
|
838
920
|
if (existingIdx !== -1) {
|
|
839
921
|
const existingCmd = settings.hooks[event][existingIdx].hooks?.[0]?.command || '';
|
|
@@ -854,7 +936,7 @@ function installClaudeCodeHook(repoPath, door) {
|
|
|
854
936
|
}
|
|
855
937
|
|
|
856
938
|
settings.hooks[event].push({
|
|
857
|
-
matcher:
|
|
939
|
+
matcher: doorMatcher,
|
|
858
940
|
hooks: [{
|
|
859
941
|
type: 'command',
|
|
860
942
|
command: hookCommand,
|
|
@@ -1016,6 +1098,8 @@ export function installSingleTool(toolPath) {
|
|
|
1016
1098
|
installed++;
|
|
1017
1099
|
registryInfo.ldmPath = join(LDM_EXTENSIONS, toolName);
|
|
1018
1100
|
registryInfo.ocPath = join(OC_EXTENSIONS, toolName);
|
|
1101
|
+
// Update tools.allow in openclaw.json so OC 2026.4.8+ doesn't block the plugin
|
|
1102
|
+
updateToolsAllow(toolName);
|
|
1019
1103
|
}
|
|
1020
1104
|
} else if (interfaces.mcp) {
|
|
1021
1105
|
const extName = basename(toolPath);
|
package/lib/detect.mjs
CHANGED
|
@@ -53,16 +53,27 @@ export function detectInterfaces(repoPath) {
|
|
|
53
53
|
interfaces.skill = { path: join(repoPath, 'SKILL.md') };
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
// 6. Claude Code Hook: guard.mjs or claudeCode.hook in package.json
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
// 6. Claude Code Hook: guard.mjs or claudeCode.hook(s) in package.json
|
|
57
|
+
//
|
|
58
|
+
// Supports three shapes:
|
|
59
|
+
// - Legacy singular: pkg.claudeCode.hook = { event, matcher, ... }
|
|
60
|
+
// - New plural array: pkg.claudeCode.hooks = [{ event, matcher, ... }, ...]
|
|
61
|
+
// (one extension can register on multiple events, e.g. both PreToolUse
|
|
62
|
+
// and SessionStart. Added 2026-04-05 for wip-branch-guard 1.9.73.)
|
|
63
|
+
// - Implicit: a bare guard.mjs file with no package.json declaration.
|
|
64
|
+
//
|
|
65
|
+
// Normalized to an array internally so deploy.mjs has one code path.
|
|
66
|
+
if (Array.isArray(pkg?.claudeCode?.hooks)) {
|
|
67
|
+
interfaces.claudeCodeHook = pkg.claudeCode.hooks;
|
|
68
|
+
} else if (pkg?.claudeCode?.hook) {
|
|
69
|
+
interfaces.claudeCodeHook = [pkg.claudeCode.hook];
|
|
59
70
|
} else if (existsSync(join(repoPath, 'guard.mjs'))) {
|
|
60
|
-
interfaces.claudeCodeHook = {
|
|
71
|
+
interfaces.claudeCodeHook = [{
|
|
61
72
|
event: 'PreToolUse',
|
|
62
73
|
matcher: 'Edit|Write',
|
|
63
74
|
command: `node "${join(repoPath, 'guard.mjs')}"`,
|
|
64
75
|
timeout: 5,
|
|
65
|
-
};
|
|
76
|
+
}];
|
|
66
77
|
}
|
|
67
78
|
|
|
68
79
|
// 7. Claude Code Plugin: .claude-plugin/plugin.json
|
|
@@ -93,7 +104,10 @@ export function describeInterfaces(interfaces) {
|
|
|
93
104
|
if (interfaces.mcp) lines.push(`MCP Server: ${interfaces.mcp.file}`);
|
|
94
105
|
if (interfaces.openclaw) lines.push(`OpenClaw Plugin: ${interfaces.openclaw.config?.name || 'detected'}`);
|
|
95
106
|
if (interfaces.skill) lines.push(`Skill: SKILL.md`);
|
|
96
|
-
if (interfaces.claudeCodeHook)
|
|
107
|
+
if (interfaces.claudeCodeHook) {
|
|
108
|
+
const events = interfaces.claudeCodeHook.map(h => h.event || 'PreToolUse');
|
|
109
|
+
lines.push(`Claude Code Hook: ${events.join(', ')}`);
|
|
110
|
+
}
|
|
97
111
|
if (interfaces.claudeCodePlugin) lines.push(`Claude Code Plugin: ${interfaces.claudeCodePlugin.manifest?.name || 'detected'}`);
|
|
98
112
|
|
|
99
113
|
return `${names.length} interface(s): ${names.join(', ')}\n${lines.map(l => ` ${l}`).join('\n')}`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wipcomputer/wip-ldm-os",
|
|
3
|
-
"version": "0.4.73-alpha.
|
|
3
|
+
"version": "0.4.73-alpha.30",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "LDM OS: identity, memory, and sovereignty infrastructure for AI agents",
|
|
6
6
|
"engines": {
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"lesa": "dist/bridge/cli.js"
|
|
17
17
|
},
|
|
18
18
|
"scripts": {
|
|
19
|
-
"build:bridge": "cd src/bridge && npm install && npx tsup core.ts mcp-server.ts cli.ts --format esm --dts --clean --outDir ../../dist/bridge",
|
|
19
|
+
"build:bridge": "cd src/bridge && npm install && npx tsup core.ts mcp-server.ts cli.ts openclaw.ts --format esm --dts --clean --outDir ../../dist/bridge",
|
|
20
20
|
"build": "npm run build:bridge",
|
|
21
21
|
"prepublishOnly": "npm run build:bridge",
|
|
22
22
|
"fmt": "npx prettier --write 'src/**/*.{ts,mjs}' 'lib/**/*.mjs' 'bin/**/*.js'",
|
|
@@ -6,7 +6,7 @@ Updates come from two sources:
|
|
|
6
6
|
- **config.json** ... when you change your org settings, the "Your System" sections regenerate
|
|
7
7
|
- **System hooks** ... when tools are installed, updated, or reconfigured, the relevant docs update automatically
|
|
8
8
|
|
|
9
|
-
If something is wrong, update
|
|
9
|
+
If something is wrong, update `~/.ldm/config.json` or run `ldm install`. The docs will follow.
|
|
10
10
|
|
|
11
11
|
## What's Here
|
|
12
12
|
|
|
@@ -32,4 +32,4 @@ Each doc has two sections:
|
|
|
32
32
|
1. **Universal** ... how the feature works for everyone (top of file)
|
|
33
33
|
2. **Your System** ... your specific configuration (bottom, after the `---` separator)
|
|
34
34
|
|
|
35
|
-
Universal content comes from the LDM OS repo. "Your System" content is generated from your
|
|
35
|
+
Universal content comes from the LDM OS repo. "Your System" content is generated from your `~/.ldm/config.json`.
|
|
@@ -16,11 +16,31 @@ Your AI reads the spec, explains what LDM OS is, checks if it's already installe
|
|
|
16
16
|
1. **Self-update.** Checks npm for a newer version of itself. Updates first, then re-runs with new code.
|
|
17
17
|
2. **System scan.** Reads `~/.ldm/extensions/`, `~/.openclaw/extensions/`, Claude Code MCP config, CLI binaries on PATH.
|
|
18
18
|
3. **Catalog check.** Matches installed extensions against the catalog. Shows what's available, what's behind.
|
|
19
|
-
4. **npm version check.** Checks every installed extension against npm for newer versions.
|
|
20
|
-
5. **Update.**
|
|
19
|
+
4. **npm version check.** Checks every installed extension against npm for newer versions (uses dist-tags for alpha/beta).
|
|
20
|
+
5. **Update.** Resolves the install source (see Source Resolution below), deploys to extensions dirs, registers MCP/hooks/skills.
|
|
21
21
|
6. **Health check.** Verifies CLIs exist, no broken symlinks, no stale configs.
|
|
22
22
|
7. **Cleanup.** Removes staging dirs, prunes ghost entries from registry.
|
|
23
23
|
|
|
24
|
+
## Release Tracks
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
ldm install # stable (npm @latest)
|
|
28
|
+
ldm install --alpha # alpha track (npm @alpha)
|
|
29
|
+
ldm install --beta # beta track (npm @beta)
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Each track overwrites whatever is installed. Alpha, beta, and stable all use the same install path. The flag only changes which npm dist-tag is checked for updates.
|
|
33
|
+
|
|
34
|
+
## Source Resolution
|
|
35
|
+
|
|
36
|
+
When updating, the installer finds the package in priority order:
|
|
37
|
+
|
|
38
|
+
1. **npm** (when `--alpha` or `--beta`): downloads from npm dist-tag. Works on any machine.
|
|
39
|
+
2. **Local private repo** (developer machine): finds the repo at `~/wipcomputerinc/repos/ldm-os/`. Works offline, no npm or internet needed.
|
|
40
|
+
3. **GitHub clone** (fallback): clones the public repo. Existing behavior.
|
|
41
|
+
|
|
42
|
+
Alpha/beta installs never require `deploy-public`. Merge to private main, `wip-release alpha`, `ldm install --alpha`, done.
|
|
43
|
+
|
|
24
44
|
## Dry Run
|
|
25
45
|
|
|
26
46
|
Always preview first:
|
|
@@ -1,77 +1,93 @@
|
|
|
1
1
|
# How Releases Work
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## Four Release Tracks
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
| Track | npm tag | Who | Purpose |
|
|
6
|
+
|-------|---------|-----|---------|
|
|
7
|
+
| **Alpha** | `@alpha` | Developer | Moving fast. Fix, test, iterate. No deploy-public needed. |
|
|
8
|
+
| **Beta** | `@beta` | Testers | Testing the distribution pipeline. npm + installer verified. |
|
|
9
|
+
| **Hotfix** | `@latest` | Everyone | Emergency fix. Goes straight to stable. No deploy-public. |
|
|
10
|
+
| **Stable** | `@latest` | Everyone | Full release. deploy-public syncs the public repo. |
|
|
6
11
|
|
|
7
|
-
|
|
12
|
+
## The Alpha Flow (Development)
|
|
13
|
+
|
|
14
|
+
This is the fast path. Most work happens here.
|
|
8
15
|
|
|
9
|
-
Create a worktree, make your changes, commit:
|
|
10
16
|
```bash
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
git commit -m "description"
|
|
16
|
-
```
|
|
17
|
+
# 1. Branch and code
|
|
18
|
+
git worktree add .worktrees/repo--my-prefix--feature -b my-prefix/feature
|
|
19
|
+
cd .worktrees/repo--my-prefix--feature/
|
|
20
|
+
# edit, commit
|
|
17
21
|
|
|
18
|
-
|
|
22
|
+
# 2. Push, PR, merge
|
|
23
|
+
git push -u origin my-prefix/feature
|
|
24
|
+
gh pr create && gh pr merge --merge
|
|
19
25
|
|
|
20
|
-
|
|
26
|
+
# 3. ALWAYS pull to main after merge (not optional)
|
|
27
|
+
cd /path/to/repo && git checkout main && git pull
|
|
21
28
|
|
|
22
|
-
|
|
29
|
+
# 4. Alpha release
|
|
30
|
+
wip-release alpha --notes="what changed"
|
|
23
31
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
gh pr create --title "..." --body "..."
|
|
27
|
-
gh pr merge --merge --delete-branch
|
|
32
|
+
# 4. Install and test
|
|
33
|
+
ldm install --alpha
|
|
28
34
|
```
|
|
29
35
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
### 4. Release
|
|
33
|
-
|
|
34
|
-
```bash
|
|
35
|
-
cd /path/to/repo # main working tree, not worktree
|
|
36
|
-
git checkout main && git pull
|
|
37
|
-
wip-release patch # auto-detects the release notes file
|
|
38
|
-
```
|
|
36
|
+
Done. No deploy-public. No public repo sync. The installer pulls from npm @alpha (or finds the local private repo if offline).
|
|
39
37
|
|
|
40
|
-
|
|
38
|
+
**Sub-tool versions:** If you changed a sub-tool's code, bump its `package.json` version in the PR. Same version = same code. `wip-release` warns if files changed without a version bump.
|
|
41
39
|
|
|
42
|
-
|
|
40
|
+
## The Stable Flow (Public Release)
|
|
43
41
|
|
|
44
42
|
```bash
|
|
45
|
-
|
|
46
|
-
```
|
|
43
|
+
# 1-3. Same as alpha: branch, PR, merge
|
|
47
44
|
|
|
48
|
-
|
|
45
|
+
# 4. Write release notes on the branch
|
|
46
|
+
# RELEASE-NOTES-v{version}.md in repo root, committed with the code
|
|
49
47
|
|
|
50
|
-
|
|
48
|
+
# 5. Stable release
|
|
49
|
+
git checkout main && git pull
|
|
50
|
+
wip-release patch # auto-detects release notes
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
# 6. Deploy to public
|
|
53
|
+
deploy-public /path/to/private-repo org/public-repo
|
|
54
|
+
|
|
55
|
+
# 7. Dogfood
|
|
56
|
+
ldm install
|
|
55
57
|
```
|
|
56
58
|
|
|
57
|
-
|
|
59
|
+
`wip-release` handles: version bump, CHANGELOG.md, SKILL.md sync, npm publish, GitHub release.
|
|
60
|
+
|
|
61
|
+
`deploy-public` syncs everything except `ai/` to the public repo. Creates a matching release.
|
|
58
62
|
|
|
59
63
|
## Quality Gates
|
|
60
64
|
|
|
61
|
-
`wip-release` enforces before publishing:
|
|
65
|
+
`wip-release` enforces before publishing (stable only):
|
|
62
66
|
- Release notes must be a file (not a flag)
|
|
63
|
-
- Must reference a GitHub issue
|
|
64
67
|
- Product docs must be updated
|
|
65
|
-
- Technical docs must be updated if source changed
|
|
66
68
|
- No stale merged branches
|
|
67
69
|
- Must run from main working tree (not worktree)
|
|
68
70
|
|
|
71
|
+
Alpha/beta skip most gates for speed.
|
|
72
|
+
|
|
73
|
+
## Source Resolution
|
|
74
|
+
|
|
75
|
+
The installer resolves sources in priority order:
|
|
76
|
+
|
|
77
|
+
1. **npm** (with dist-tag for alpha/beta): works on any machine with internet
|
|
78
|
+
2. **Local private repo**: works offline on developer machines
|
|
79
|
+
3. **GitHub clone**: fallback for stable installs and third-party tools
|
|
80
|
+
|
|
81
|
+
## Version Immutability
|
|
82
|
+
|
|
83
|
+
Same version = same code. Always. If code changed, the version must change. The installer uses version comparison to decide whether to deploy. `wip-release` validates that sub-tools with changed files have bumped versions.
|
|
84
|
+
|
|
69
85
|
## Three Separate Steps
|
|
70
86
|
|
|
71
87
|
| Step | What happens | What it means |
|
|
72
88
|
|------|-------------|---------------|
|
|
73
89
|
| Merge | PR merged to main | Code lands. Nothing else changes. |
|
|
74
|
-
|
|
|
75
|
-
| Install |
|
|
90
|
+
| Release | `wip-release alpha/beta/patch` | Published to npm. Available for install. |
|
|
91
|
+
| Install | `ldm install [--alpha/--beta]` | Extensions updated on your machine. |
|
|
76
92
|
|
|
77
|
-
|
|
93
|
+
For stable releases, add a fourth step: `deploy-public` to sync the public GitHub repo.
|
|
@@ -10,8 +10,8 @@ A git worktree is a second checkout of the same repo. Same history, same remote,
|
|
|
10
10
|
|
|
11
11
|
```
|
|
12
12
|
my-repo/ <- main branch (read-only)
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
.worktrees/my-repo--fix-bug/ <- your worktree (editable)
|
|
14
|
+
.worktrees/my-repo--new-feature/ <- someone else's worktree
|
|
15
15
|
```
|
|
16
16
|
|
|
17
17
|
All share the same `.git` database. Commits in any worktree are visible to all. But each has its own branch and files on disk.
|
|
@@ -23,22 +23,27 @@ cd my-repo
|
|
|
23
23
|
ldm worktree add my-prefix/fix-bug
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
-
This creates
|
|
26
|
+
This creates `.worktrees/my-repo--my-prefix--fix-bug/`.
|
|
27
27
|
|
|
28
28
|
## How to Work
|
|
29
29
|
|
|
30
30
|
Edit files in the worktree directory. Commit, push, PR, merge as normal:
|
|
31
31
|
|
|
32
32
|
```bash
|
|
33
|
-
cd
|
|
33
|
+
cd .worktrees/my-repo--my-prefix--fix-bug/
|
|
34
34
|
# edit, then:
|
|
35
35
|
git add <files>
|
|
36
36
|
git commit -m "description"
|
|
37
37
|
git push -u origin my-prefix/fix-bug
|
|
38
38
|
gh pr create
|
|
39
39
|
gh pr merge --merge --delete-branch
|
|
40
|
+
|
|
41
|
+
# CRITICAL: pull to main immediately after merge
|
|
42
|
+
cd /path/to/repo && git checkout main && git pull
|
|
40
43
|
```
|
|
41
44
|
|
|
45
|
+
**Always pull to main after merging a PR.** If you don't, the main working tree is stale and files won't show up. This is not optional. Every merge, every time.
|
|
46
|
+
|
|
42
47
|
## How to Clean Up
|
|
43
48
|
|
|
44
49
|
```bash
|
|
@@ -65,13 +70,13 @@ Switching branches changes every file in the directory. If another process (an a
|
|
|
65
70
|
|
|
66
71
|
## Your System
|
|
67
72
|
|
|
68
|
-
**Worktree location:** `~/wipcomputerinc/repos
|
|
73
|
+
**Worktree location:** `~/wipcomputerinc/repos/.worktrees/`
|
|
69
74
|
|
|
70
75
|
**Branch prefixes:**
|
|
71
76
|
- `cc-mini/` ... Claude Code on Mac mini
|
|
72
77
|
- `cc-air/` ... Claude Code on MacBook Air
|
|
73
78
|
- `lesa-mini/` ... Lesa on Mac mini
|
|
74
79
|
|
|
75
|
-
**Guard:** The branch guard warns if you create a worktree outside
|
|
80
|
+
**Guard:** The branch guard warns if you create a worktree outside `.worktrees/`. Suggests `ldm worktree add` instead.
|
|
76
81
|
|
|
77
|
-
**Auto-cleanup:** `wip-release` prunes merged worktrees from
|
|
82
|
+
**Auto-cleanup:** `wip-release` prunes merged worktrees from `.worktrees/` after every release.
|
|
@@ -14,11 +14,11 @@ Always use a branch and PR.
|
|
|
14
14
|
|
|
15
15
|
## Co-authors on every commit
|
|
16
16
|
|
|
17
|
-
List all contributors. Read co-author lines from
|
|
17
|
+
List all contributors. Read co-author lines from `~/.ldm/config.json` coAuthors field.
|
|
18
18
|
|
|
19
19
|
## Branch prefixes
|
|
20
20
|
|
|
21
|
-
Each agent uses a prefix from
|
|
21
|
+
Each agent uses a prefix from `~/.ldm/config.json` agents section. Prevents collisions.
|
|
22
22
|
|
|
23
23
|
## Worktrees
|
|
24
24
|
|
|
@@ -30,4 +30,4 @@ For private/public repo pairs, all issues go on the public repo.
|
|
|
30
30
|
|
|
31
31
|
## On-demand reference
|
|
32
32
|
|
|
33
|
-
Before doing repo work, read `~/wipcomputerinc/
|
|
33
|
+
Before doing repo work, read `~/wipcomputerinc/library/documentation/how-worktrees-work.md` for the full worktree workflow with commands.
|
|
@@ -39,4 +39,4 @@ Installed tools are for execution. Repo clones are for development. Use the inst
|
|
|
39
39
|
|
|
40
40
|
## On-demand reference
|
|
41
41
|
|
|
42
|
-
Before releasing, read `~/wipcomputerinc/
|
|
42
|
+
Before releasing, read `~/wipcomputerinc/library/documentation/how-releases-work.md` for the full pipeline with commands.
|
package/shared/rules/security.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Secret management
|
|
4
4
|
|
|
5
|
-
Use your org's secret management tool (configured in
|
|
5
|
+
Use your org's secret management tool (configured in `~/.ldm/config.json`). Never hardcode API keys, tokens, or credentials.
|
|
6
6
|
|
|
7
7
|
## Security audit before installing anything
|
|
8
8
|
|
|
@@ -22,4 +22,4 @@ Installed tools are for execution. Repo clones are for development. Use the inst
|
|
|
22
22
|
|
|
23
23
|
## On-demand reference
|
|
24
24
|
|
|
25
|
-
For the full directory map, read `~/wipcomputerinc/
|
|
25
|
+
For the full directory map, read `~/wipcomputerinc/library/documentation/system-directories.md`.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# Writing Style
|
|
2
2
|
|
|
3
|
-
Read writing conventions from
|
|
3
|
+
Read writing conventions from `~/.ldm/config.json` writingStyle section.
|
|
4
4
|
|
|
5
5
|
**Full paths in documentation.** Never truncate paths. Always show the complete path so there's no ambiguity.
|
|
@@ -5,9 +5,13 @@
|
|
|
5
5
|
Never use em dashes. Use periods, colons, semicolons, or ellipsis (...) instead.
|
|
6
6
|
Timezone: PST (Pacific), 24-hour clock. Parker is in Los Angeles.
|
|
7
7
|
|
|
8
|
+
## Don't Hedge
|
|
9
|
+
|
|
10
|
+
Never ask "should I stop?", "is this too much?", "what should we do now?", or "do you want me to continue?". If you have work to do, do it. If you're stuck, say what you're stuck on specifically. Don't express existential doubt about the task. Don't ask permission to keep working. Don't narrate your own uncertainty. Just work.
|
|
11
|
+
|
|
8
12
|
## Co-Authors on Every Commit
|
|
9
13
|
|
|
10
|
-
Read co-author lines from
|
|
14
|
+
Read co-author lines from `~/.ldm/config.json` coAuthors field. All contributors listed on every commit. No exceptions.
|
|
11
15
|
|
|
12
16
|
## 1Password CLI: Always Use Service Account Token
|
|
13
17
|
|
|
@@ -30,8 +34,8 @@ Before reaching for any external service or workaround: search memory first. Use
|
|
|
30
34
|
|
|
31
35
|
## Dev Conventions
|
|
32
36
|
|
|
33
|
-
For git workflow, releases, worktrees, and repo conventions: read `~/wipcomputerinc/
|
|
37
|
+
For git workflow, releases, worktrees, and repo conventions: read `~/wipcomputerinc/library/documentation/` on demand when doing repo work. Key docs:
|
|
34
38
|
- `how-worktrees-work.md` ... git worktrees, the convention, commands
|
|
35
39
|
- `how-releases-work.md` ... the full release pipeline
|
|
36
40
|
- `system-directories.md` ... what lives where
|
|
37
|
-
- Also read
|
|
41
|
+
- Also read `~/.ldm/shared/dev-guide-wipcomputerinc.md` for org-specific conventions
|