botinabox 0.2.5 → 0.3.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/CHANGELOG.md +9 -0
- package/dist/index.js +626 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,15 @@ Format: [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Versioning: [S
|
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
+
## [0.3.0] — 2026-04-03
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- **Domain tables** — `defineDomainTables(db, options?)` creates standard multi-agent app tables: org, project, client, invoice, repository, file, channel, rule, event + junction tables. Configurable: disable clients, repos, files, channels, rules, or events.
|
|
14
|
+
- **Domain entity contexts** — `defineDomainEntityContexts(db, options?)` renders per-entity context directories for all domain tables. Projects get REPOS.md + RULES.md. Clients get REPOS.md + AGENTS.md + INVOICES.md.
|
|
15
|
+
- **Claude stream parser** — `parseClaudeStream(stdout)` parses Claude CLI NDJSON output into structured results (session, model, cost, tokens, text, errors). Plus `isMaxTurns()`, `isLoginRequired()`, `deactivateLocalImagePaths()`.
|
|
16
|
+
- **Process env builder** — `buildProcessEnv(allowedKeys?, inject?)` creates a clean subprocess environment with only safe variables. Strips all secrets.
|
|
17
|
+
|
|
9
18
|
## [0.2.0] — 2026-04-03
|
|
10
19
|
|
|
11
20
|
### Added
|
package/dist/index.js
CHANGED
|
@@ -1673,6 +1673,501 @@ ${s.definition}` : null,
|
|
|
1673
1673
|
});
|
|
1674
1674
|
}
|
|
1675
1675
|
|
|
1676
|
+
// src/core/data/domain-schema.ts
|
|
1677
|
+
function defineDomainTables(db, options = {}) {
|
|
1678
|
+
const opts = {
|
|
1679
|
+
clients: true,
|
|
1680
|
+
repositories: true,
|
|
1681
|
+
files: true,
|
|
1682
|
+
channels: true,
|
|
1683
|
+
rules: true,
|
|
1684
|
+
events: true,
|
|
1685
|
+
...options
|
|
1686
|
+
};
|
|
1687
|
+
db.define("org", {
|
|
1688
|
+
columns: {
|
|
1689
|
+
id: "TEXT PRIMARY KEY",
|
|
1690
|
+
name: "TEXT NOT NULL",
|
|
1691
|
+
type: "TEXT NOT NULL DEFAULT 'company'",
|
|
1692
|
+
description: "TEXT",
|
|
1693
|
+
mission: "TEXT",
|
|
1694
|
+
website: "TEXT",
|
|
1695
|
+
created_at: "TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP",
|
|
1696
|
+
updated_at: "TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP",
|
|
1697
|
+
deleted_at: "TEXT"
|
|
1698
|
+
}
|
|
1699
|
+
});
|
|
1700
|
+
db.define("project", {
|
|
1701
|
+
columns: {
|
|
1702
|
+
id: "TEXT PRIMARY KEY",
|
|
1703
|
+
org_id: "TEXT NOT NULL",
|
|
1704
|
+
name: "TEXT NOT NULL",
|
|
1705
|
+
status: "TEXT",
|
|
1706
|
+
description: "TEXT",
|
|
1707
|
+
tech_stack: "TEXT",
|
|
1708
|
+
github_repo: "TEXT",
|
|
1709
|
+
deploy_target: "TEXT",
|
|
1710
|
+
production_url: "TEXT",
|
|
1711
|
+
branch_strategy: "TEXT",
|
|
1712
|
+
notes: "TEXT",
|
|
1713
|
+
created_at: "TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP",
|
|
1714
|
+
updated_at: "TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP",
|
|
1715
|
+
deleted_at: "TEXT"
|
|
1716
|
+
}
|
|
1717
|
+
});
|
|
1718
|
+
db.define("agent_project", {
|
|
1719
|
+
columns: {
|
|
1720
|
+
agent_id: "TEXT NOT NULL",
|
|
1721
|
+
project_id: "TEXT NOT NULL",
|
|
1722
|
+
role: "TEXT",
|
|
1723
|
+
created_at: "TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP"
|
|
1724
|
+
},
|
|
1725
|
+
primaryKey: ["agent_id", "project_id"]
|
|
1726
|
+
});
|
|
1727
|
+
db.define("secret_project", {
|
|
1728
|
+
columns: {
|
|
1729
|
+
secret_id: "TEXT NOT NULL",
|
|
1730
|
+
project_id: "TEXT NOT NULL",
|
|
1731
|
+
created_at: "TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP"
|
|
1732
|
+
},
|
|
1733
|
+
primaryKey: ["secret_id", "project_id"]
|
|
1734
|
+
});
|
|
1735
|
+
db.define("secret_org", {
|
|
1736
|
+
columns: {
|
|
1737
|
+
secret_id: "TEXT NOT NULL",
|
|
1738
|
+
org_id: "TEXT NOT NULL",
|
|
1739
|
+
created_at: "TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP"
|
|
1740
|
+
},
|
|
1741
|
+
primaryKey: ["secret_id", "org_id"]
|
|
1742
|
+
});
|
|
1743
|
+
if (opts.clients) {
|
|
1744
|
+
db.define("client", {
|
|
1745
|
+
columns: {
|
|
1746
|
+
id: "TEXT PRIMARY KEY",
|
|
1747
|
+
org_id: "TEXT NOT NULL",
|
|
1748
|
+
name: "TEXT NOT NULL",
|
|
1749
|
+
contact_name: "TEXT",
|
|
1750
|
+
contact_email: "TEXT",
|
|
1751
|
+
phone: "TEXT",
|
|
1752
|
+
status: "TEXT NOT NULL DEFAULT 'active'",
|
|
1753
|
+
notes: "TEXT",
|
|
1754
|
+
created_at: "TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP",
|
|
1755
|
+
updated_at: "TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP",
|
|
1756
|
+
deleted_at: "TEXT"
|
|
1757
|
+
}
|
|
1758
|
+
});
|
|
1759
|
+
db.define("invoice", {
|
|
1760
|
+
columns: {
|
|
1761
|
+
id: "TEXT PRIMARY KEY",
|
|
1762
|
+
org_id: "TEXT NOT NULL",
|
|
1763
|
+
client_id: "TEXT NOT NULL",
|
|
1764
|
+
number: "TEXT",
|
|
1765
|
+
amount_cents: "INTEGER",
|
|
1766
|
+
currency: "TEXT DEFAULT 'USD'",
|
|
1767
|
+
status: "TEXT NOT NULL DEFAULT 'draft'",
|
|
1768
|
+
description: "TEXT",
|
|
1769
|
+
hours: "REAL",
|
|
1770
|
+
rate_cents: "INTEGER",
|
|
1771
|
+
items_json: "TEXT",
|
|
1772
|
+
issued_at: "TEXT",
|
|
1773
|
+
due_at: "TEXT",
|
|
1774
|
+
paid_at: "TEXT",
|
|
1775
|
+
notes: "TEXT",
|
|
1776
|
+
created_at: "TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP",
|
|
1777
|
+
updated_at: "TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP",
|
|
1778
|
+
deleted_at: "TEXT"
|
|
1779
|
+
},
|
|
1780
|
+
tableConstraints: [
|
|
1781
|
+
"CREATE INDEX IF NOT EXISTS idx_invoice_client ON invoice(client_id)"
|
|
1782
|
+
]
|
|
1783
|
+
});
|
|
1784
|
+
db.define("agent_client", {
|
|
1785
|
+
columns: {
|
|
1786
|
+
agent_id: "TEXT NOT NULL",
|
|
1787
|
+
client_id: "TEXT NOT NULL",
|
|
1788
|
+
created_at: "TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP"
|
|
1789
|
+
},
|
|
1790
|
+
primaryKey: ["agent_id", "client_id"]
|
|
1791
|
+
});
|
|
1792
|
+
}
|
|
1793
|
+
if (opts.repositories) {
|
|
1794
|
+
db.define("repository", {
|
|
1795
|
+
columns: {
|
|
1796
|
+
id: "TEXT PRIMARY KEY",
|
|
1797
|
+
org_id: "TEXT NOT NULL",
|
|
1798
|
+
project_id: "TEXT",
|
|
1799
|
+
client_id: "TEXT",
|
|
1800
|
+
name: "TEXT NOT NULL",
|
|
1801
|
+
url: "TEXT",
|
|
1802
|
+
local_path: "TEXT",
|
|
1803
|
+
default_branch: "TEXT DEFAULT 'main'",
|
|
1804
|
+
platform: "TEXT DEFAULT 'github'",
|
|
1805
|
+
status: "TEXT NOT NULL DEFAULT 'active'",
|
|
1806
|
+
notes: "TEXT",
|
|
1807
|
+
created_at: "TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP",
|
|
1808
|
+
updated_at: "TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP",
|
|
1809
|
+
deleted_at: "TEXT"
|
|
1810
|
+
},
|
|
1811
|
+
tableConstraints: [
|
|
1812
|
+
"CREATE INDEX IF NOT EXISTS idx_repository_project ON repository(project_id)",
|
|
1813
|
+
"CREATE INDEX IF NOT EXISTS idx_repository_client ON repository(client_id)"
|
|
1814
|
+
]
|
|
1815
|
+
});
|
|
1816
|
+
}
|
|
1817
|
+
if (opts.files) {
|
|
1818
|
+
db.define("file", {
|
|
1819
|
+
columns: {
|
|
1820
|
+
id: "TEXT PRIMARY KEY",
|
|
1821
|
+
org_id: "TEXT",
|
|
1822
|
+
name: "TEXT NOT NULL",
|
|
1823
|
+
file_path: "TEXT",
|
|
1824
|
+
mime_type: "TEXT",
|
|
1825
|
+
size_bytes: "INTEGER",
|
|
1826
|
+
project_id: "TEXT",
|
|
1827
|
+
access_level: "TEXT NOT NULL DEFAULT 'org'",
|
|
1828
|
+
description: "TEXT",
|
|
1829
|
+
notes: "TEXT",
|
|
1830
|
+
created_at: "TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP",
|
|
1831
|
+
updated_at: "TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP",
|
|
1832
|
+
deleted_at: "TEXT"
|
|
1833
|
+
}
|
|
1834
|
+
});
|
|
1835
|
+
}
|
|
1836
|
+
if (opts.channels) {
|
|
1837
|
+
db.define("channel", {
|
|
1838
|
+
columns: {
|
|
1839
|
+
id: "TEXT PRIMARY KEY",
|
|
1840
|
+
org_id: "TEXT",
|
|
1841
|
+
platform: "TEXT NOT NULL",
|
|
1842
|
+
external_id: "TEXT",
|
|
1843
|
+
name: "TEXT NOT NULL",
|
|
1844
|
+
type: "TEXT NOT NULL DEFAULT 'channel'",
|
|
1845
|
+
instructions: "TEXT",
|
|
1846
|
+
created_at: "TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP",
|
|
1847
|
+
updated_at: "TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP",
|
|
1848
|
+
deleted_at: "TEXT"
|
|
1849
|
+
}
|
|
1850
|
+
});
|
|
1851
|
+
}
|
|
1852
|
+
if (opts.rules) {
|
|
1853
|
+
db.define("rule", {
|
|
1854
|
+
columns: {
|
|
1855
|
+
id: "TEXT PRIMARY KEY",
|
|
1856
|
+
org_id: "TEXT",
|
|
1857
|
+
title: "TEXT NOT NULL",
|
|
1858
|
+
rule_text: "TEXT NOT NULL",
|
|
1859
|
+
scope: "TEXT NOT NULL DEFAULT 'org'",
|
|
1860
|
+
category: "TEXT NOT NULL DEFAULT 'process'",
|
|
1861
|
+
priority: "INTEGER NOT NULL DEFAULT 50",
|
|
1862
|
+
created_at: "TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP",
|
|
1863
|
+
updated_at: "TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP",
|
|
1864
|
+
deleted_at: "TEXT"
|
|
1865
|
+
}
|
|
1866
|
+
});
|
|
1867
|
+
db.define("rule_agent", {
|
|
1868
|
+
columns: {
|
|
1869
|
+
rule_id: "TEXT NOT NULL",
|
|
1870
|
+
agent_id: "TEXT NOT NULL",
|
|
1871
|
+
created_at: "TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP"
|
|
1872
|
+
},
|
|
1873
|
+
primaryKey: ["rule_id", "agent_id"]
|
|
1874
|
+
});
|
|
1875
|
+
db.define("rule_project", {
|
|
1876
|
+
columns: {
|
|
1877
|
+
rule_id: "TEXT NOT NULL",
|
|
1878
|
+
project_id: "TEXT NOT NULL",
|
|
1879
|
+
created_at: "TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP"
|
|
1880
|
+
},
|
|
1881
|
+
primaryKey: ["rule_id", "project_id"]
|
|
1882
|
+
});
|
|
1883
|
+
db.define("rule_org", {
|
|
1884
|
+
columns: {
|
|
1885
|
+
rule_id: "TEXT NOT NULL",
|
|
1886
|
+
org_id: "TEXT NOT NULL",
|
|
1887
|
+
created_at: "TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP"
|
|
1888
|
+
},
|
|
1889
|
+
primaryKey: ["rule_id", "org_id"]
|
|
1890
|
+
});
|
|
1891
|
+
}
|
|
1892
|
+
if (opts.events) {
|
|
1893
|
+
db.define("event", {
|
|
1894
|
+
columns: {
|
|
1895
|
+
id: "TEXT PRIMARY KEY",
|
|
1896
|
+
org_id: "TEXT",
|
|
1897
|
+
type: "TEXT NOT NULL",
|
|
1898
|
+
summary: "TEXT NOT NULL",
|
|
1899
|
+
details: "TEXT",
|
|
1900
|
+
severity: "TEXT NOT NULL DEFAULT 'info'",
|
|
1901
|
+
actor_agent_id: "TEXT",
|
|
1902
|
+
actor_user_id: "TEXT",
|
|
1903
|
+
project_id: "TEXT",
|
|
1904
|
+
channel_id: "TEXT",
|
|
1905
|
+
created_at: "TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP",
|
|
1906
|
+
deleted_at: "TEXT"
|
|
1907
|
+
},
|
|
1908
|
+
tableConstraints: [
|
|
1909
|
+
"CREATE INDEX IF NOT EXISTS idx_event_type ON event(type, created_at)",
|
|
1910
|
+
"CREATE INDEX IF NOT EXISTS idx_event_project ON event(project_id)"
|
|
1911
|
+
]
|
|
1912
|
+
});
|
|
1913
|
+
}
|
|
1914
|
+
}
|
|
1915
|
+
|
|
1916
|
+
// src/core/data/domain-entity-contexts.ts
|
|
1917
|
+
function defineDomainEntityContexts(db, options = {}) {
|
|
1918
|
+
const opts = {
|
|
1919
|
+
clients: true,
|
|
1920
|
+
repositories: true,
|
|
1921
|
+
files: true,
|
|
1922
|
+
channels: true,
|
|
1923
|
+
rules: true,
|
|
1924
|
+
...options
|
|
1925
|
+
};
|
|
1926
|
+
db.defineEntityContext("org", {
|
|
1927
|
+
table: "org",
|
|
1928
|
+
directory: "orgs",
|
|
1929
|
+
slugColumn: "name",
|
|
1930
|
+
indexFile: "orgs/ORGS.md",
|
|
1931
|
+
files: {
|
|
1932
|
+
"ORG.md": {
|
|
1933
|
+
source: { type: "self" },
|
|
1934
|
+
render: (rows) => {
|
|
1935
|
+
const o = rows[0];
|
|
1936
|
+
if (!o) return "";
|
|
1937
|
+
return [
|
|
1938
|
+
`# ${o.name}`,
|
|
1939
|
+
"",
|
|
1940
|
+
o.type ? `**Type:** ${o.type}` : null,
|
|
1941
|
+
o.description ? `
|
|
1942
|
+
${o.description}` : null,
|
|
1943
|
+
o.mission ? `
|
|
1944
|
+
**Mission:** ${o.mission}` : null,
|
|
1945
|
+
o.website ? `**Website:** ${o.website}` : null,
|
|
1946
|
+
""
|
|
1947
|
+
].filter(Boolean).join("\n");
|
|
1948
|
+
}
|
|
1949
|
+
}
|
|
1950
|
+
}
|
|
1951
|
+
});
|
|
1952
|
+
db.defineEntityContext("project", {
|
|
1953
|
+
table: "project",
|
|
1954
|
+
directory: "projects",
|
|
1955
|
+
slugColumn: "name",
|
|
1956
|
+
indexFile: "projects/PROJECTS.md",
|
|
1957
|
+
files: {
|
|
1958
|
+
"PROJECT.md": {
|
|
1959
|
+
source: { type: "self" },
|
|
1960
|
+
render: (rows) => {
|
|
1961
|
+
const p = rows[0];
|
|
1962
|
+
if (!p) return "";
|
|
1963
|
+
return [
|
|
1964
|
+
`# ${p.name}`,
|
|
1965
|
+
"",
|
|
1966
|
+
p.status ? `**Status:** ${p.status}` : null,
|
|
1967
|
+
p.description ? `
|
|
1968
|
+
${p.description}` : null,
|
|
1969
|
+
p.tech_stack ? `
|
|
1970
|
+
**Tech Stack:** ${p.tech_stack}` : null,
|
|
1971
|
+
p.production_url ? `**URL:** ${p.production_url}` : null,
|
|
1972
|
+
p.github_repo ? `**GitHub:** ${p.github_repo}` : null,
|
|
1973
|
+
p.deploy_target ? `**Deploy:** ${p.deploy_target}` : null,
|
|
1974
|
+
p.branch_strategy ? `**Branch Strategy:** ${p.branch_strategy}` : null,
|
|
1975
|
+
p.notes ? `
|
|
1976
|
+
**Notes:**
|
|
1977
|
+
${p.notes}` : null,
|
|
1978
|
+
""
|
|
1979
|
+
].filter(Boolean).join("\n");
|
|
1980
|
+
}
|
|
1981
|
+
},
|
|
1982
|
+
...opts.repositories ? {
|
|
1983
|
+
"REPOS.md": {
|
|
1984
|
+
source: {
|
|
1985
|
+
type: "hasMany",
|
|
1986
|
+
table: "repository",
|
|
1987
|
+
foreignKey: "project_id"
|
|
1988
|
+
},
|
|
1989
|
+
render: (rows) => {
|
|
1990
|
+
if (!rows.length) return "";
|
|
1991
|
+
const lines = rows.map(
|
|
1992
|
+
(r) => `- **${r.name}** \u2014 ${r.url ?? ""}`
|
|
1993
|
+
);
|
|
1994
|
+
return `# Repositories
|
|
1995
|
+
|
|
1996
|
+
${lines.join("\n")}
|
|
1997
|
+
`;
|
|
1998
|
+
},
|
|
1999
|
+
omitIfEmpty: true
|
|
2000
|
+
}
|
|
2001
|
+
} : {},
|
|
2002
|
+
...opts.rules ? {
|
|
2003
|
+
"RULES.md": {
|
|
2004
|
+
source: {
|
|
2005
|
+
type: "manyToMany",
|
|
2006
|
+
junctionTable: "rule_project",
|
|
2007
|
+
localKey: "project_id",
|
|
2008
|
+
remoteKey: "rule_id",
|
|
2009
|
+
remoteTable: "rule",
|
|
2010
|
+
softDelete: true,
|
|
2011
|
+
orderBy: "priority"
|
|
2012
|
+
},
|
|
2013
|
+
render: (rows) => {
|
|
2014
|
+
if (!rows.length) return "";
|
|
2015
|
+
const lines = rows.map(
|
|
2016
|
+
(r) => `### ${r.title}
|
|
2017
|
+
${r.rule_text}`
|
|
2018
|
+
);
|
|
2019
|
+
return `# Project Rules
|
|
2020
|
+
|
|
2021
|
+
${lines.join("\n\n")}
|
|
2022
|
+
`;
|
|
2023
|
+
},
|
|
2024
|
+
omitIfEmpty: true
|
|
2025
|
+
}
|
|
2026
|
+
} : {}
|
|
2027
|
+
}
|
|
2028
|
+
});
|
|
2029
|
+
if (opts.clients) {
|
|
2030
|
+
db.defineEntityContext("client", {
|
|
2031
|
+
table: "client",
|
|
2032
|
+
directory: "clients",
|
|
2033
|
+
slugColumn: "name",
|
|
2034
|
+
indexFile: "clients/CLIENTS.md",
|
|
2035
|
+
files: {
|
|
2036
|
+
"CLIENT.md": {
|
|
2037
|
+
source: { type: "self" },
|
|
2038
|
+
render: (rows) => {
|
|
2039
|
+
const c = rows[0];
|
|
2040
|
+
if (!c) return "";
|
|
2041
|
+
return [
|
|
2042
|
+
`# ${c.name}`,
|
|
2043
|
+
"",
|
|
2044
|
+
c.contact_name ? `**Contact:** ${c.contact_name}` : null,
|
|
2045
|
+
c.contact_email ? `**Email:** ${c.contact_email}` : null,
|
|
2046
|
+
c.phone ? `**Phone:** ${c.phone}` : null,
|
|
2047
|
+
c.status ? `**Status:** ${c.status}` : null,
|
|
2048
|
+
c.notes ? `
|
|
2049
|
+
${c.notes}` : null,
|
|
2050
|
+
""
|
|
2051
|
+
].filter(Boolean).join("\n");
|
|
2052
|
+
}
|
|
2053
|
+
},
|
|
2054
|
+
...opts.repositories ? {
|
|
2055
|
+
"REPOS.md": {
|
|
2056
|
+
source: {
|
|
2057
|
+
type: "hasMany",
|
|
2058
|
+
table: "repository",
|
|
2059
|
+
foreignKey: "client_id"
|
|
2060
|
+
},
|
|
2061
|
+
render: (rows) => {
|
|
2062
|
+
if (!rows.length) return "";
|
|
2063
|
+
const lines = rows.map(
|
|
2064
|
+
(r) => `- **${r.name}** \u2014 ${r.url ?? ""}`
|
|
2065
|
+
);
|
|
2066
|
+
return `# Repositories
|
|
2067
|
+
|
|
2068
|
+
${lines.join("\n")}
|
|
2069
|
+
`;
|
|
2070
|
+
},
|
|
2071
|
+
omitIfEmpty: true
|
|
2072
|
+
}
|
|
2073
|
+
} : {},
|
|
2074
|
+
AGENTS: {
|
|
2075
|
+
source: {
|
|
2076
|
+
type: "manyToMany",
|
|
2077
|
+
junctionTable: "agent_client",
|
|
2078
|
+
localKey: "client_id",
|
|
2079
|
+
remoteKey: "agent_id",
|
|
2080
|
+
remoteTable: "agents"
|
|
2081
|
+
},
|
|
2082
|
+
render: (rows) => {
|
|
2083
|
+
if (!rows.length) return "";
|
|
2084
|
+
const lines = rows.map(
|
|
2085
|
+
(r) => `- **${r.name}** (${r.role ?? "agent"})`
|
|
2086
|
+
);
|
|
2087
|
+
return `# Assigned Agents
|
|
2088
|
+
|
|
2089
|
+
${lines.join("\n")}
|
|
2090
|
+
`;
|
|
2091
|
+
},
|
|
2092
|
+
omitIfEmpty: true
|
|
2093
|
+
},
|
|
2094
|
+
"INVOICES.md": {
|
|
2095
|
+
source: {
|
|
2096
|
+
type: "hasMany",
|
|
2097
|
+
table: "invoice",
|
|
2098
|
+
foreignKey: "client_id"
|
|
2099
|
+
},
|
|
2100
|
+
render: (rows) => {
|
|
2101
|
+
if (!rows.length) return "";
|
|
2102
|
+
const lines = rows.map((r) => {
|
|
2103
|
+
const amt = r.amount_cents ? `$${(r.amount_cents / 100).toFixed(2)}` : "TBD";
|
|
2104
|
+
return `- **${r.number ?? "Draft"}** \u2014 ${amt} (${r.status})${r.description ? ": " + r.description : ""}`;
|
|
2105
|
+
});
|
|
2106
|
+
return `# Invoices
|
|
2107
|
+
|
|
2108
|
+
${lines.join("\n")}
|
|
2109
|
+
`;
|
|
2110
|
+
},
|
|
2111
|
+
omitIfEmpty: true
|
|
2112
|
+
}
|
|
2113
|
+
}
|
|
2114
|
+
});
|
|
2115
|
+
}
|
|
2116
|
+
if (opts.files) {
|
|
2117
|
+
db.defineEntityContext("file", {
|
|
2118
|
+
table: "file",
|
|
2119
|
+
directory: "files",
|
|
2120
|
+
slugColumn: "name",
|
|
2121
|
+
indexFile: "files/FILES.md",
|
|
2122
|
+
files: {
|
|
2123
|
+
"FILE.md": {
|
|
2124
|
+
source: { type: "self" },
|
|
2125
|
+
render: (rows) => {
|
|
2126
|
+
const f = rows[0];
|
|
2127
|
+
if (!f) return "";
|
|
2128
|
+
return [
|
|
2129
|
+
`# ${f.name}`,
|
|
2130
|
+
"",
|
|
2131
|
+
f.mime_type ? `**Type:** ${f.mime_type}` : null,
|
|
2132
|
+
f.access_level ? `**Access:** ${f.access_level}` : null,
|
|
2133
|
+
f.file_path ? `**Path:** ${f.file_path}` : null,
|
|
2134
|
+
f.description ? `
|
|
2135
|
+
${f.description}` : null,
|
|
2136
|
+
""
|
|
2137
|
+
].filter(Boolean).join("\n");
|
|
2138
|
+
}
|
|
2139
|
+
}
|
|
2140
|
+
}
|
|
2141
|
+
});
|
|
2142
|
+
}
|
|
2143
|
+
if (opts.channels) {
|
|
2144
|
+
db.defineEntityContext("channel", {
|
|
2145
|
+
table: "channel",
|
|
2146
|
+
directory: "channels",
|
|
2147
|
+
slugColumn: "name",
|
|
2148
|
+
indexFile: "channels/CHANNELS.md",
|
|
2149
|
+
files: {
|
|
2150
|
+
"CHANNEL.md": {
|
|
2151
|
+
source: { type: "self" },
|
|
2152
|
+
render: (rows) => {
|
|
2153
|
+
const c = rows[0];
|
|
2154
|
+
if (!c) return "";
|
|
2155
|
+
return [
|
|
2156
|
+
`# ${c.name}`,
|
|
2157
|
+
"",
|
|
2158
|
+
c.platform ? `**Platform:** ${c.platform}` : null,
|
|
2159
|
+
c.type ? `**Type:** ${c.type}` : null,
|
|
2160
|
+
c.instructions ? `
|
|
2161
|
+
${c.instructions}` : null,
|
|
2162
|
+
""
|
|
2163
|
+
].filter(Boolean).join("\n");
|
|
2164
|
+
}
|
|
2165
|
+
}
|
|
2166
|
+
}
|
|
2167
|
+
});
|
|
2168
|
+
}
|
|
2169
|
+
}
|
|
2170
|
+
|
|
1676
2171
|
// src/core/security/sanitizer.ts
|
|
1677
2172
|
import { Buffer as Buffer2 } from "buffer";
|
|
1678
2173
|
var DEFAULT_FIELD_LIMIT = 65535;
|
|
@@ -1756,6 +2251,44 @@ var AuditEmitter = class {
|
|
|
1756
2251
|
}
|
|
1757
2252
|
};
|
|
1758
2253
|
|
|
2254
|
+
// src/core/security/process-env.ts
|
|
2255
|
+
var DEFAULT_ALLOWED_KEYS = /* @__PURE__ */ new Set([
|
|
2256
|
+
"PATH",
|
|
2257
|
+
"HOME",
|
|
2258
|
+
"USER",
|
|
2259
|
+
"SHELL",
|
|
2260
|
+
"LANG",
|
|
2261
|
+
"TERM",
|
|
2262
|
+
"TMPDIR",
|
|
2263
|
+
"XDG_RUNTIME_DIR",
|
|
2264
|
+
"NODE_ENV",
|
|
2265
|
+
// Git
|
|
2266
|
+
"GIT_AUTHOR_NAME",
|
|
2267
|
+
"GIT_AUTHOR_EMAIL",
|
|
2268
|
+
"GIT_COMMITTER_NAME",
|
|
2269
|
+
"GIT_COMMITTER_EMAIL",
|
|
2270
|
+
// Homebrew / system
|
|
2271
|
+
"HOMEBREW_PREFIX",
|
|
2272
|
+
"HOMEBREW_CELLAR",
|
|
2273
|
+
"HOMEBREW_REPOSITORY"
|
|
2274
|
+
]);
|
|
2275
|
+
function buildProcessEnv(allowedKeys, inject) {
|
|
2276
|
+
const allowed = new Set(DEFAULT_ALLOWED_KEYS);
|
|
2277
|
+
if (allowedKeys) {
|
|
2278
|
+
for (const k of allowedKeys) allowed.add(k);
|
|
2279
|
+
}
|
|
2280
|
+
const env = {};
|
|
2281
|
+
for (const [key, value] of Object.entries(process.env)) {
|
|
2282
|
+
if (allowed.has(key) && value !== void 0) {
|
|
2283
|
+
env[key] = value;
|
|
2284
|
+
}
|
|
2285
|
+
}
|
|
2286
|
+
if (inject) {
|
|
2287
|
+
Object.assign(env, inject);
|
|
2288
|
+
}
|
|
2289
|
+
return env;
|
|
2290
|
+
}
|
|
2291
|
+
|
|
1759
2292
|
// src/core/update/version-utils.ts
|
|
1760
2293
|
function parseVersion(v) {
|
|
1761
2294
|
const cleaned = v.replace(/^v/, "").split("-")[0] ?? v;
|
|
@@ -3233,6 +3766,92 @@ var SecretStore = class {
|
|
|
3233
3766
|
};
|
|
3234
3767
|
}
|
|
3235
3768
|
};
|
|
3769
|
+
|
|
3770
|
+
// src/core/orchestrator/claude-stream-parser.ts
|
|
3771
|
+
function parseClaudeStream(stdout) {
|
|
3772
|
+
let sessionId = null;
|
|
3773
|
+
let model = null;
|
|
3774
|
+
let costUsd = null;
|
|
3775
|
+
let usage = null;
|
|
3776
|
+
let isError = false;
|
|
3777
|
+
let errorMessage = null;
|
|
3778
|
+
let stopReason = null;
|
|
3779
|
+
const textBlocks = [];
|
|
3780
|
+
for (const line of stdout.split("\n")) {
|
|
3781
|
+
if (!line.trim()) continue;
|
|
3782
|
+
let event;
|
|
3783
|
+
try {
|
|
3784
|
+
event = JSON.parse(line);
|
|
3785
|
+
} catch {
|
|
3786
|
+
continue;
|
|
3787
|
+
}
|
|
3788
|
+
const type = event.type;
|
|
3789
|
+
if (type === "system" && event.subtype === "init") {
|
|
3790
|
+
sessionId = event.session_id ?? null;
|
|
3791
|
+
model = event.model ?? null;
|
|
3792
|
+
}
|
|
3793
|
+
if (type === "assistant") {
|
|
3794
|
+
const msg = event.message;
|
|
3795
|
+
const content = msg?.content ?? event.content;
|
|
3796
|
+
if (Array.isArray(content)) {
|
|
3797
|
+
for (const block of content) {
|
|
3798
|
+
if (block.type === "text" && block.text) {
|
|
3799
|
+
textBlocks.push(block.text);
|
|
3800
|
+
}
|
|
3801
|
+
}
|
|
3802
|
+
}
|
|
3803
|
+
}
|
|
3804
|
+
if (type === "result") {
|
|
3805
|
+
isError = !!event.is_error;
|
|
3806
|
+
stopReason = event.stop_reason ?? null;
|
|
3807
|
+
costUsd = typeof event.total_cost_usd === "number" ? event.total_cost_usd : null;
|
|
3808
|
+
const u = event.usage;
|
|
3809
|
+
if (u) {
|
|
3810
|
+
usage = {
|
|
3811
|
+
inputTokens: u.input_tokens ?? 0,
|
|
3812
|
+
cachedInputTokens: u.cache_read_input_tokens ?? 0,
|
|
3813
|
+
outputTokens: u.output_tokens ?? 0
|
|
3814
|
+
};
|
|
3815
|
+
}
|
|
3816
|
+
if (isError) {
|
|
3817
|
+
errorMessage = event.error ?? event.result ?? "Unknown error";
|
|
3818
|
+
}
|
|
3819
|
+
const resultContent = event.result;
|
|
3820
|
+
if (typeof resultContent === "string" && resultContent) {
|
|
3821
|
+
textBlocks.push(resultContent);
|
|
3822
|
+
}
|
|
3823
|
+
}
|
|
3824
|
+
}
|
|
3825
|
+
return {
|
|
3826
|
+
sessionId,
|
|
3827
|
+
model,
|
|
3828
|
+
costUsd,
|
|
3829
|
+
usage,
|
|
3830
|
+
summary: textBlocks.join("\n"),
|
|
3831
|
+
isError,
|
|
3832
|
+
errorMessage,
|
|
3833
|
+
stopReason
|
|
3834
|
+
};
|
|
3835
|
+
}
|
|
3836
|
+
function isMaxTurns(parsed) {
|
|
3837
|
+
return parsed.stopReason === "max_turns" || parsed.stopReason === "tool_use";
|
|
3838
|
+
}
|
|
3839
|
+
function isLoginRequired(stdout) {
|
|
3840
|
+
const patterns = [
|
|
3841
|
+
"not logged in",
|
|
3842
|
+
"login required",
|
|
3843
|
+
"authentication required",
|
|
3844
|
+
"please log in"
|
|
3845
|
+
];
|
|
3846
|
+
const lower = stdout.toLowerCase();
|
|
3847
|
+
return patterns.some((p) => lower.includes(p));
|
|
3848
|
+
}
|
|
3849
|
+
function deactivateLocalImagePaths(prompt) {
|
|
3850
|
+
return prompt.replace(
|
|
3851
|
+
/(?<=\s|^)(\/[\w./-]+\.(?:png|jpg|jpeg|gif|webp|svg))(?=\s|$)/gi,
|
|
3852
|
+
"[image-path:$1]"
|
|
3853
|
+
);
|
|
3854
|
+
}
|
|
3236
3855
|
export {
|
|
3237
3856
|
AGENT_STATUSES,
|
|
3238
3857
|
AgentRegistry,
|
|
@@ -3275,6 +3894,7 @@ export {
|
|
|
3275
3894
|
areDependenciesMet,
|
|
3276
3895
|
buildAgentBindings,
|
|
3277
3896
|
buildChainOrigin,
|
|
3897
|
+
buildProcessEnv,
|
|
3278
3898
|
checkAllowlist,
|
|
3279
3899
|
checkChainDepth,
|
|
3280
3900
|
checkMentionGate,
|
|
@@ -3282,8 +3902,11 @@ export {
|
|
|
3282
3902
|
classifyUpdate,
|
|
3283
3903
|
compareVersions,
|
|
3284
3904
|
createConfigRevision,
|
|
3905
|
+
deactivateLocalImagePaths,
|
|
3285
3906
|
defineCoreEntityContexts,
|
|
3286
3907
|
defineCoreTables,
|
|
3908
|
+
defineDomainEntityContexts,
|
|
3909
|
+
defineDomainTables,
|
|
3287
3910
|
detectCycle,
|
|
3288
3911
|
discoverChannels,
|
|
3289
3912
|
discoverProviders,
|
|
@@ -3292,7 +3915,10 @@ export {
|
|
|
3292
3915
|
initConfig,
|
|
3293
3916
|
interpolate,
|
|
3294
3917
|
interpolateEnv,
|
|
3918
|
+
isLoginRequired,
|
|
3919
|
+
isMaxTurns,
|
|
3295
3920
|
loadConfig,
|
|
3921
|
+
parseClaudeStream,
|
|
3296
3922
|
parseVersion,
|
|
3297
3923
|
runPackageMigrations,
|
|
3298
3924
|
sanitize,
|