clawcompany 0.3.0 → 0.4.0
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/dist/index.js +275 -85
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -9,89 +9,6 @@ var __export = (target, all) => {
|
|
|
9
9
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
10
|
};
|
|
11
11
|
|
|
12
|
-
// src/utils.ts
|
|
13
|
-
import { join } from "path";
|
|
14
|
-
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
|
|
15
|
-
function banner() {
|
|
16
|
-
console.log("");
|
|
17
|
-
console.log(" \u{1F99E} ClawCompany v0.3.0");
|
|
18
|
-
console.log(" Build for OPC. Every human being is a chairman.");
|
|
19
|
-
console.log("");
|
|
20
|
-
}
|
|
21
|
-
function getConfigDir() {
|
|
22
|
-
const dir = join(process.env.HOME ?? "~", ".clawcompany");
|
|
23
|
-
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
24
|
-
return dir;
|
|
25
|
-
}
|
|
26
|
-
function getConfigPath() {
|
|
27
|
-
return join(getConfigDir(), "config.json");
|
|
28
|
-
}
|
|
29
|
-
function configExists() {
|
|
30
|
-
return existsSync(getConfigPath());
|
|
31
|
-
}
|
|
32
|
-
function readConfig() {
|
|
33
|
-
if (!configExists()) return null;
|
|
34
|
-
try {
|
|
35
|
-
return JSON.parse(readFileSync(getConfigPath(), "utf-8"));
|
|
36
|
-
} catch {
|
|
37
|
-
return null;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
function writeConfig(config) {
|
|
41
|
-
writeFileSync(getConfigPath(), JSON.stringify(config, null, 2));
|
|
42
|
-
}
|
|
43
|
-
async function apiGet(path, port = 3200) {
|
|
44
|
-
const res = await fetch(`http://localhost:${port}${path}`);
|
|
45
|
-
if (!res.ok) throw new Error(`API error: ${res.status}`);
|
|
46
|
-
return res.json();
|
|
47
|
-
}
|
|
48
|
-
async function apiPost(path, body, port = 3200) {
|
|
49
|
-
const res = await fetch(`http://localhost:${port}${path}`, {
|
|
50
|
-
method: "POST",
|
|
51
|
-
headers: { "Content-Type": "application/json" },
|
|
52
|
-
body: JSON.stringify(body)
|
|
53
|
-
});
|
|
54
|
-
if (!res.ok) {
|
|
55
|
-
const err = await res.json().catch(() => ({ error: `HTTP ${res.status}` }));
|
|
56
|
-
throw new Error(err.error ?? `API error: ${res.status}`);
|
|
57
|
-
}
|
|
58
|
-
return res.json();
|
|
59
|
-
}
|
|
60
|
-
async function validateClawApiKey(key) {
|
|
61
|
-
try {
|
|
62
|
-
const res = await fetch("https://clawapi.org/api/v1/chat/completions", {
|
|
63
|
-
method: "POST",
|
|
64
|
-
headers: {
|
|
65
|
-
"Authorization": `Bearer ${key}`,
|
|
66
|
-
"Content-Type": "application/json"
|
|
67
|
-
},
|
|
68
|
-
body: JSON.stringify({
|
|
69
|
-
model: "gpt-oss-20b",
|
|
70
|
-
messages: [{ role: "user", content: "hi" }],
|
|
71
|
-
max_tokens: 5
|
|
72
|
-
})
|
|
73
|
-
});
|
|
74
|
-
if (res.status === 401) return { valid: false, error: "Invalid key. Check your key at clawapi.org" };
|
|
75
|
-
if (!res.ok) return { valid: false, error: `ClawAPI returned ${res.status}. Try again later.` };
|
|
76
|
-
return { valid: true };
|
|
77
|
-
} catch (err) {
|
|
78
|
-
return { valid: false, error: `Cannot reach ClawAPI: ${err.message}. Check your internet connection.` };
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
async function isServerRunning(port = 3200) {
|
|
82
|
-
try {
|
|
83
|
-
const res = await fetch(`http://localhost:${port}/api/health`);
|
|
84
|
-
return res.ok;
|
|
85
|
-
} catch {
|
|
86
|
-
return false;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
var init_utils = __esm({
|
|
90
|
-
"src/utils.ts"() {
|
|
91
|
-
"use strict";
|
|
92
|
-
}
|
|
93
|
-
});
|
|
94
|
-
|
|
95
12
|
// ../packages/shared/src/types.ts
|
|
96
13
|
var init_types = __esm({
|
|
97
14
|
"../packages/shared/src/types.ts"() {
|
|
@@ -856,6 +773,153 @@ var init_market = __esm({
|
|
|
856
773
|
}
|
|
857
774
|
});
|
|
858
775
|
|
|
776
|
+
// ../packages/shared/src/memory.ts
|
|
777
|
+
function createEmptyMemory() {
|
|
778
|
+
return {
|
|
779
|
+
version: 1,
|
|
780
|
+
chairman: {
|
|
781
|
+
domains: [],
|
|
782
|
+
commonMissions: [],
|
|
783
|
+
preferences: []
|
|
784
|
+
},
|
|
785
|
+
company: {
|
|
786
|
+
missionCount: 0,
|
|
787
|
+
learnings: [],
|
|
788
|
+
domainKnowledge: [],
|
|
789
|
+
goodPatterns: [],
|
|
790
|
+
recentMissions: []
|
|
791
|
+
},
|
|
792
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
793
|
+
};
|
|
794
|
+
}
|
|
795
|
+
function buildMemoryContext(memory) {
|
|
796
|
+
const parts = [];
|
|
797
|
+
const ch = memory.chairman;
|
|
798
|
+
if (ch.language) parts.push(`Chairman language: ${ch.language}`);
|
|
799
|
+
if (ch.outputStyle) parts.push(`Output style: ${ch.outputStyle}`);
|
|
800
|
+
if (ch.domains.length > 0) parts.push(`Focus areas: ${ch.domains.slice(0, 5).join(", ")}`);
|
|
801
|
+
if (ch.preferences.length > 0) parts.push(`Preferences: ${ch.preferences.slice(0, 5).join("; ")}`);
|
|
802
|
+
const co = memory.company;
|
|
803
|
+
if (co.missionCount > 0) parts.push(`Missions completed: ${co.missionCount}`);
|
|
804
|
+
if (co.learnings.length > 0) parts.push(`Key learnings: ${co.learnings.slice(-5).join("; ")}`);
|
|
805
|
+
if (co.domainKnowledge.length > 0) parts.push(`Domain knowledge: ${co.domainKnowledge.slice(-5).join("; ")}`);
|
|
806
|
+
if (co.recentMissions.length > 0) {
|
|
807
|
+
const recent = co.recentMissions.slice(-3).map((m) => m.goal).join("; ");
|
|
808
|
+
parts.push(`Recent missions: ${recent}`);
|
|
809
|
+
}
|
|
810
|
+
if (parts.length === 0) return "";
|
|
811
|
+
return `
|
|
812
|
+
|
|
813
|
+
## Company Memory
|
|
814
|
+
${parts.join("\n")}`;
|
|
815
|
+
}
|
|
816
|
+
function updateMemoryFromMission(memory, mission, chairmanMessage) {
|
|
817
|
+
const updated = structuredClone(memory);
|
|
818
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
819
|
+
updated.updatedAt = now;
|
|
820
|
+
if (chairmanMessage || mission.goal) {
|
|
821
|
+
const text = chairmanMessage ?? mission.goal;
|
|
822
|
+
const hasChinese = /[\u4e00-\u9fff]/.test(text);
|
|
823
|
+
const hasJapanese = /[\u3040-\u309f\u30a0-\u30ff]/.test(text);
|
|
824
|
+
if (hasChinese) updated.chairman.language = "zh";
|
|
825
|
+
else if (hasJapanese) updated.chairman.language = "ja";
|
|
826
|
+
else if (!updated.chairman.language) updated.chairman.language = "en";
|
|
827
|
+
}
|
|
828
|
+
const domainKeywords = extractDomains(mission.goal);
|
|
829
|
+
for (const d of domainKeywords) {
|
|
830
|
+
if (!updated.chairman.domains.includes(d)) {
|
|
831
|
+
updated.chairman.domains.push(d);
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
if (updated.chairman.domains.length > 10) {
|
|
835
|
+
updated.chairman.domains = updated.chairman.domains.slice(-10);
|
|
836
|
+
}
|
|
837
|
+
const missionType = classifyMission(mission.goal);
|
|
838
|
+
if (missionType && !updated.chairman.commonMissions.includes(missionType)) {
|
|
839
|
+
updated.chairman.commonMissions.push(missionType);
|
|
840
|
+
}
|
|
841
|
+
if (updated.chairman.commonMissions.length > 8) {
|
|
842
|
+
updated.chairman.commonMissions = updated.chairman.commonMissions.slice(-8);
|
|
843
|
+
}
|
|
844
|
+
updated.company.missionCount++;
|
|
845
|
+
const rolesUsed = [...new Set(mission.workStreams.map((ws) => ws.assignedTo))];
|
|
846
|
+
updated.company.recentMissions.push({
|
|
847
|
+
goal: mission.goal.slice(0, 100),
|
|
848
|
+
date: now.split("T")[0],
|
|
849
|
+
cost: mission.cost,
|
|
850
|
+
duration: mission.duration,
|
|
851
|
+
workStreamCount: mission.workStreams.length,
|
|
852
|
+
rolesUsed,
|
|
853
|
+
success: mission.workStreams.every((ws) => ws.status === "completed")
|
|
854
|
+
});
|
|
855
|
+
if (updated.company.recentMissions.length > 10) {
|
|
856
|
+
updated.company.recentMissions = updated.company.recentMissions.slice(-10);
|
|
857
|
+
}
|
|
858
|
+
return updated;
|
|
859
|
+
}
|
|
860
|
+
function extractDomains(text) {
|
|
861
|
+
const domains = [];
|
|
862
|
+
const lower = text.toLowerCase();
|
|
863
|
+
const domainMap = {
|
|
864
|
+
bitcoin: "crypto",
|
|
865
|
+
btc: "crypto",
|
|
866
|
+
ethereum: "crypto",
|
|
867
|
+
eth: "crypto",
|
|
868
|
+
"\u6BD4\u7279\u5E01": "crypto",
|
|
869
|
+
"\u4EE5\u592A\u574A": "crypto",
|
|
870
|
+
"\u52A0\u5BC6": "crypto",
|
|
871
|
+
defi: "crypto",
|
|
872
|
+
crypto: "crypto",
|
|
873
|
+
trading: "finance",
|
|
874
|
+
investment: "finance",
|
|
875
|
+
revenue: "finance",
|
|
876
|
+
stock: "finance",
|
|
877
|
+
market: "finance",
|
|
878
|
+
ai: "ai/ml",
|
|
879
|
+
"machine learning": "ai/ml",
|
|
880
|
+
llm: "ai/ml",
|
|
881
|
+
agent: "ai/ml",
|
|
882
|
+
"\u4EBA\u5DE5\u667A\u80FD": "ai/ml",
|
|
883
|
+
marketing: "marketing",
|
|
884
|
+
seo: "marketing",
|
|
885
|
+
content: "marketing",
|
|
886
|
+
brand: "marketing",
|
|
887
|
+
"\u8425\u9500": "marketing",
|
|
888
|
+
code: "engineering",
|
|
889
|
+
api: "engineering",
|
|
890
|
+
software: "engineering",
|
|
891
|
+
deploy: "engineering",
|
|
892
|
+
legal: "legal",
|
|
893
|
+
contract: "legal",
|
|
894
|
+
compliance: "legal",
|
|
895
|
+
ecommerce: "ecommerce",
|
|
896
|
+
product: "ecommerce",
|
|
897
|
+
shopify: "ecommerce"
|
|
898
|
+
};
|
|
899
|
+
for (const [keyword, domain] of Object.entries(domainMap)) {
|
|
900
|
+
if (lower.includes(keyword) && !domains.includes(domain)) {
|
|
901
|
+
domains.push(domain);
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
return domains;
|
|
905
|
+
}
|
|
906
|
+
function classifyMission(goal) {
|
|
907
|
+
const lower = goal.toLowerCase();
|
|
908
|
+
if (lower.includes("analyz") || lower.includes("\u5206\u6790")) return "analysis";
|
|
909
|
+
if (lower.includes("research") || lower.includes("\u7814\u7A76") || lower.includes("\u8C03\u7814")) return "research";
|
|
910
|
+
if (lower.includes("write") || lower.includes("draft") || lower.includes("\u5199")) return "writing";
|
|
911
|
+
if (lower.includes("compare") || lower.includes("\u5BF9\u6BD4") || lower.includes("\u6BD4\u8F83")) return "comparison";
|
|
912
|
+
if (lower.includes("build") || lower.includes("create") || lower.includes("\u5F00\u53D1")) return "building";
|
|
913
|
+
if (lower.includes("plan") || lower.includes("strategy") || lower.includes("\u7B56\u7565")) return "strategy";
|
|
914
|
+
if (lower.includes("price") || lower.includes("cost") || lower.includes("\u4EF7\u683C")) return "pricing";
|
|
915
|
+
return null;
|
|
916
|
+
}
|
|
917
|
+
var init_memory = __esm({
|
|
918
|
+
"../packages/shared/src/memory.ts"() {
|
|
919
|
+
"use strict";
|
|
920
|
+
}
|
|
921
|
+
});
|
|
922
|
+
|
|
859
923
|
// ../packages/shared/src/index.ts
|
|
860
924
|
var init_src = __esm({
|
|
861
925
|
"../packages/shared/src/index.ts"() {
|
|
@@ -864,6 +928,106 @@ var init_src = __esm({
|
|
|
864
928
|
init_defaults();
|
|
865
929
|
init_api_paths();
|
|
866
930
|
init_market();
|
|
931
|
+
init_memory();
|
|
932
|
+
}
|
|
933
|
+
});
|
|
934
|
+
|
|
935
|
+
// src/utils.ts
|
|
936
|
+
import { join } from "path";
|
|
937
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
|
|
938
|
+
function banner() {
|
|
939
|
+
console.log("");
|
|
940
|
+
console.log(" \u{1F99E} ClawCompany v0.1.0");
|
|
941
|
+
console.log(" Build for OPC. Every human being is a chairman.");
|
|
942
|
+
console.log("");
|
|
943
|
+
}
|
|
944
|
+
function getConfigDir() {
|
|
945
|
+
const dir = join(process.env.HOME ?? "~", ".clawcompany");
|
|
946
|
+
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
947
|
+
return dir;
|
|
948
|
+
}
|
|
949
|
+
function getConfigPath() {
|
|
950
|
+
return join(getConfigDir(), "config.json");
|
|
951
|
+
}
|
|
952
|
+
function configExists() {
|
|
953
|
+
return existsSync(getConfigPath());
|
|
954
|
+
}
|
|
955
|
+
function readConfig() {
|
|
956
|
+
if (!configExists()) return null;
|
|
957
|
+
try {
|
|
958
|
+
return JSON.parse(readFileSync(getConfigPath(), "utf-8"));
|
|
959
|
+
} catch {
|
|
960
|
+
return null;
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
function writeConfig(config) {
|
|
964
|
+
writeFileSync(getConfigPath(), JSON.stringify(config, null, 2));
|
|
965
|
+
}
|
|
966
|
+
function getMemoryPath() {
|
|
967
|
+
return join(getConfigDir(), "memory.json");
|
|
968
|
+
}
|
|
969
|
+
function readMemory() {
|
|
970
|
+
try {
|
|
971
|
+
if (existsSync(getMemoryPath())) {
|
|
972
|
+
return JSON.parse(readFileSync(getMemoryPath(), "utf-8"));
|
|
973
|
+
}
|
|
974
|
+
} catch {
|
|
975
|
+
}
|
|
976
|
+
return createEmptyMemory();
|
|
977
|
+
}
|
|
978
|
+
function writeMemory(memory) {
|
|
979
|
+
writeFileSync(getMemoryPath(), JSON.stringify(memory, null, 2));
|
|
980
|
+
}
|
|
981
|
+
async function apiGet(path, port = 3200) {
|
|
982
|
+
const res = await fetch(`http://localhost:${port}${path}`);
|
|
983
|
+
if (!res.ok) throw new Error(`API error: ${res.status}`);
|
|
984
|
+
return res.json();
|
|
985
|
+
}
|
|
986
|
+
async function apiPost(path, body, port = 3200) {
|
|
987
|
+
const res = await fetch(`http://localhost:${port}${path}`, {
|
|
988
|
+
method: "POST",
|
|
989
|
+
headers: { "Content-Type": "application/json" },
|
|
990
|
+
body: JSON.stringify(body)
|
|
991
|
+
});
|
|
992
|
+
if (!res.ok) {
|
|
993
|
+
const err = await res.json().catch(() => ({ error: `HTTP ${res.status}` }));
|
|
994
|
+
throw new Error(err.error ?? `API error: ${res.status}`);
|
|
995
|
+
}
|
|
996
|
+
return res.json();
|
|
997
|
+
}
|
|
998
|
+
async function validateClawApiKey(key) {
|
|
999
|
+
try {
|
|
1000
|
+
const res = await fetch("https://clawapi.org/api/v1/chat/completions", {
|
|
1001
|
+
method: "POST",
|
|
1002
|
+
headers: {
|
|
1003
|
+
"Authorization": `Bearer ${key}`,
|
|
1004
|
+
"Content-Type": "application/json"
|
|
1005
|
+
},
|
|
1006
|
+
body: JSON.stringify({
|
|
1007
|
+
model: "gpt-oss-20b",
|
|
1008
|
+
messages: [{ role: "user", content: "hi" }],
|
|
1009
|
+
max_tokens: 5
|
|
1010
|
+
})
|
|
1011
|
+
});
|
|
1012
|
+
if (res.status === 401) return { valid: false, error: "Invalid key. Check your key at clawapi.org" };
|
|
1013
|
+
if (!res.ok) return { valid: false, error: `ClawAPI returned ${res.status}. Try again later.` };
|
|
1014
|
+
return { valid: true };
|
|
1015
|
+
} catch (err) {
|
|
1016
|
+
return { valid: false, error: `Cannot reach ClawAPI: ${err.message}. Check your internet connection.` };
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
async function isServerRunning(port = 3200) {
|
|
1020
|
+
try {
|
|
1021
|
+
const res = await fetch(`http://localhost:${port}/api/health`);
|
|
1022
|
+
return res.ok;
|
|
1023
|
+
} catch {
|
|
1024
|
+
return false;
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
var init_utils = __esm({
|
|
1028
|
+
"src/utils.ts"() {
|
|
1029
|
+
"use strict";
|
|
1030
|
+
init_src();
|
|
867
1031
|
}
|
|
868
1032
|
});
|
|
869
1033
|
|
|
@@ -1995,6 +2159,11 @@ var TaskOrchestrator = class {
|
|
|
1995
2159
|
this.executor = new AgentExecutor(router, new ToolExecutor());
|
|
1996
2160
|
}
|
|
1997
2161
|
executor;
|
|
2162
|
+
memoryContext = "";
|
|
2163
|
+
/** Set company memory context to inject into all agent prompts */
|
|
2164
|
+
setMemoryContext(ctx) {
|
|
2165
|
+
this.memoryContext = ctx;
|
|
2166
|
+
}
|
|
1998
2167
|
/**
|
|
1999
2168
|
* Phase 2: CEO decomposes mission into work streams.
|
|
2000
2169
|
* Human (Chairman) gives the mission → CEO breaks it down.
|
|
@@ -2013,7 +2182,8 @@ var TaskOrchestrator = class {
|
|
|
2013
2182
|
Priority: ${mission.priority}
|
|
2014
2183
|
${mission.deadline ? `Deadline: ${mission.deadline}` : ""}
|
|
2015
2184
|
${mission.budgetLimit ? `Budget limit: $${mission.budgetLimit}` : ""}
|
|
2016
|
-
|
|
2185
|
+
${this.memoryContext ? `${this.memoryContext}
|
|
2186
|
+
` : ""}
|
|
2017
2187
|
Your team:
|
|
2018
2188
|
${roleList}
|
|
2019
2189
|
|
|
@@ -2142,7 +2312,8 @@ ${truncated}
|
|
|
2142
2312
|
title: ws.title,
|
|
2143
2313
|
description: `${ws.description}
|
|
2144
2314
|
|
|
2145
|
-
Complexity: ${ws.estimatedComplexity}${context}
|
|
2315
|
+
Complexity: ${ws.estimatedComplexity}${context}${this.memoryContext ? `
|
|
2316
|
+
${this.memoryContext}` : ""}
|
|
2146
2317
|
|
|
2147
2318
|
Today's date is ${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}.`,
|
|
2148
2319
|
assignedTo: ws.assignTo,
|
|
@@ -2230,6 +2401,12 @@ async function runInProcess(goal, userConfig) {
|
|
|
2230
2401
|
await registry.loadFromConfig(clawConfig.providers);
|
|
2231
2402
|
const router = new ModelRouter(registry, clawConfig);
|
|
2232
2403
|
const orchestrator = new TaskOrchestrator(router);
|
|
2404
|
+
const memory = readMemory();
|
|
2405
|
+
const memoryCtx = buildMemoryContext(memory);
|
|
2406
|
+
if (memoryCtx) {
|
|
2407
|
+
orchestrator.setMemoryContext(memoryCtx);
|
|
2408
|
+
console.log(" \u{1F9E0} Company memory loaded\n");
|
|
2409
|
+
}
|
|
2233
2410
|
console.log(" Phase 2: CEO decomposing...");
|
|
2234
2411
|
const mission = {
|
|
2235
2412
|
id: `mission-${Date.now()}`,
|
|
@@ -2247,6 +2424,19 @@ async function runInProcess(goal, userConfig) {
|
|
|
2247
2424
|
console.log(" Phase 3-5: Executing...");
|
|
2248
2425
|
const report = await orchestrator.executeMission(mission, workStreams);
|
|
2249
2426
|
console.log(" Phase 6: Delivering to Chairman\n");
|
|
2427
|
+
const updatedMemory = updateMemoryFromMission(memory, {
|
|
2428
|
+
goal,
|
|
2429
|
+
cost: report.totalCost,
|
|
2430
|
+
duration: report.totalTimeSeconds,
|
|
2431
|
+
workStreams: report.workStreams.map((ws) => ({
|
|
2432
|
+
title: ws.title,
|
|
2433
|
+
assignedTo: ws.assignedTo,
|
|
2434
|
+
status: ws.status,
|
|
2435
|
+
output: ws.output
|
|
2436
|
+
}))
|
|
2437
|
+
}, goal);
|
|
2438
|
+
writeMemory(updatedMemory);
|
|
2439
|
+
console.log(" \u{1F9E0} Memory updated\n");
|
|
2250
2440
|
const result = {
|
|
2251
2441
|
status: "completed",
|
|
2252
2442
|
mission: report.mission,
|
package/package.json
CHANGED