Skip to content

Commit 1e0e68a

Browse files
v0.9.0
1 parent db67358 commit 1e0e68a

File tree

747 files changed

+79296
-32281
lines changed

Some content is hidden

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

747 files changed

+79296
-32281
lines changed

.github/workflows/playwright.yml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
name: Playwright Tests
2+
on:
3+
push:
4+
branches: [ main, master ]
5+
pull_request:
6+
branches: [ main, master ]
7+
jobs:
8+
test:
9+
timeout-minutes: 60
10+
runs-on: ubuntu-latest
11+
steps:
12+
- uses: actions/checkout@v4
13+
- uses: actions/setup-node@v4
14+
with:
15+
node-version: lts/*
16+
- name: Install dependencies
17+
run: npm ci
18+
- name: Install Playwright Browsers
19+
run: npx playwright install --with-deps
20+
- name: Run Playwright tests
21+
run: npx playwright test
22+
- uses: actions/upload-artifact@v4
23+
if: ${{ !cancelled() }}
24+
with:
25+
name: playwright-report
26+
path: playwright-report/
27+
retention-days: 30

.node-version

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
v22.14.0

.nvmrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
22.10.0
1+
22.14.0

.typedai.json

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
[
2+
{
3+
"baseDir": "./",
4+
"language": "typescript",
5+
"initialise": "node build.js install",
6+
"compile": "node build.js build",
7+
"format": "",
8+
"staticAnalysis": "node build.js lint",
9+
"test": "npm run test",
10+
"languageTools": "typescript",
11+
"devBranch": "main",
12+
"indexDocs": [
13+
"src/**/*.ts",
14+
"frontend/src/**/*.ts",
15+
"bin/**",
16+
"shared/**"
17+
]
18+
}
19+
]

DOCS.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,4 +256,45 @@ const checkPromises = filesToStat.map(async (filename) => {
256256
Use single line statements where reasonable. This is a good candidate is there is not much complexity, only the single if statement.
257257
The empty catch block can definitely be on a single line with the comment
258258

259+
# Example
260+
## Original code
261+
```typescript
262+
263+
// Parse the config content
264+
let config: any;
265+
try {
266+
config = yaml.load(configContent);
267+
} catch (error: any) {
268+
logger.warn(`Failed to parse YAML ${configPath}: ${error.message}`);
269+
return; // Stop if parsing fails
270+
}
259271

272+
```
273+
## Updated code
274+
```typescript
275+
276+
let config: any;
277+
try {
278+
config = yaml.load(configContent);
279+
} catch (error: any) {
280+
logger.warn(`Failed to parse YAML ${configPath}: ${error.message}`);
281+
return;
282+
}
283+
284+
```
285+
## Notes
286+
This code block does a simple load, there's no business logic.
287+
The between the `yaml.load` and the warn message is enough for the reader to quickly understand. No further comments are required.
288+
289+
# Example
290+
291+
## Orignal
292+
```
293+
const maxAttempts = 3; // Max reflection attempts
294+
```
295+
## Updated
296+
```typescript
297+
const maxReflectionAttempts = 3;
298+
```
299+
## Notes
300+
Use descriptive variable and function names instead of commenting on generic names.

Dockerfile.dev

Lines changed: 80 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,48 +3,108 @@ FROM python:3.11-slim
33

44
ENV DEBIAN_FRONTEND=noninteractive
55

6-
# Update package lists without signature verification to avoid "At least one invalid signature was encountered." on debian repos
6+
# Update package lists
77
RUN apt-get -o Acquire::Check-Valid-Until=false -o Acquire::AllowInsecureRepositories=true -o Acquire::AllowDowngradeToInsecureRepositories=true update
88

9+
# Install base dependencies + Python build dependencies for pyenv
910
# make g++ gcc build-essential are needed for node-gyp
10-
RUN apt-get install -y curl make g++ gcc build-essential git
11-
RUN curl -sL https://deb.nodesource.com/setup_20.x -o nodesource_setup.sh
12-
RUN bash ./nodesource_setup.sh
13-
RUN apt-get install -y nodejs
11+
# Others are common for building Python versions with pyenv
12+
RUN apt-get install -y --no-install-recommends \
13+
curl make g++ gcc build-essential git \
14+
libssl-dev zlib1g-dev libbz2-dev \
15+
libreadline-dev libsqlite3-dev wget llvm \
16+
libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev \
17+
&& rm -rf /var/lib/apt/lists/*
1418

15-
RUN pip install aider-chat google-cloud-aiplatform "anthropic[vertex]"
19+
# Install Node.js
20+
RUN curl -sL https://deb.nodesource.com/setup_20.x -o nodesource_setup.sh \
21+
&& bash ./nodesource_setup.sh \
22+
&& apt-get install -y nodejs \
23+
&& rm nodesource_setup.sh
1624

17-
ENV user=typedai
18-
ENV homedir=/home/typedai/
19-
RUN useradd --create-home -g users typedai
25+
# Install global Python packages
26+
RUN pip install aider-chat google-cloud-aiplatform "anthropic[vertex]" youtube-transcript-api
2027

21-
WORKDIR $homedir
28+
# Define user and home directory consistently
29+
ENV USER_NAME=typedai
30+
ENV HOMEDIR=/home/${USER_NAME}
2231

32+
# Create user with a specific home directory
33+
# Consider adding -u <UID> if you need a fixed UID, e.g., -u 1000
34+
RUN useradd --create-home -d ${HOMEDIR} -g users ${USER_NAME}
35+
36+
# Set working directory (HOMEDIR is now defined)
37+
WORKDIR ${HOMEDIR}
38+
39+
# Copy application files that are needed before USER switch or owned by root initially (if any)
40+
# For .husky and package.json, it's usually better to copy them after USER switch
41+
# so the user owns them, or chown them.
42+
43+
# Copy .python-version file from build context (TYPEDAI_HOME) to the user's home directory in the image
44+
# This must exist in your TYPEDAI_HOME directory.
45+
COPY .python-version ${HOMEDIR}/.python-version
46+
# Ensure the user will own it (important if copied before USER switch, good practice anyway)
47+
RUN chown ${USER_NAME}:users ${HOMEDIR}/.python-version
48+
49+
# Copy .husky files (assuming they are at the root of TYPEDAI_HOME)
2350
RUN mkdir ".husky"
2451
COPY .husky/install.mjs .husky/install.mjs
52+
RUN chown -R ${USER_NAME}:users ${HOMEDIR}/.husky
2553

54+
# Copy main package.json and install dependencies
2655
COPY package*.json ./
56+
# Make chown of lock file optional
57+
RUN chown ${USER_NAME}:users package.json package-lock.json 2>/dev/null || chown ${USER_NAME}:users package.json
58+
59+
# Switch to non-root user
60+
USER ${USER_NAME}
61+
62+
# Now, as the user, install npm dependencies
2763
RUN npm install
2864

2965
# Install Angular dependencies and build Angular app
30-
WORKDIR $homedir/frontend
31-
COPY frontend/package*.json ./
66+
# Ensure frontend/package.json exists in your TYPEDAI_HOME/frontend
67+
WORKDIR ${HOMEDIR}/frontend
68+
COPY --chown=${USER_NAME}:users frontend/package.json ./
69+
# COPY frontend/yarn.lock ./ # if you use yarn
70+
# If frontend/package-lock.json exists in your TYPEDAI_HOME/frontend, copy it with correct ownership.
71+
# If it doesn't exist, this COPY command will fail. If it's optional, remove this line.
72+
COPY --chown=${USER_NAME}:users frontend/package-lock.json ./
73+
3274
RUN npm install
75+
# RUN npm run build # If you need to build frontend during Docker image creation
3376

3477
# Set work directory back to home
35-
WORKDIR $homedir
78+
WORKDIR ${HOMEDIR}
3679

37-
# Switch to non-root user
38-
USER $user
80+
# Install pyenv for the typedai user
81+
RUN git clone https://github.com/pyenv/pyenv.git ${HOMEDIR}/.pyenv
82+
83+
# Add pyenv bin directory to the PATH for the typedai user
84+
ENV PYENV_ROOT="${HOMEDIR}/.pyenv"
85+
# Add shims dir too, and move comment
86+
ENV PATH="${PYENV_ROOT}/bin:${PYENV_ROOT}/shims:${PATH}"
87+
88+
# This comment was on the ENV PATH line before, moving it here:
89+
# This sets PATH for subsequent RUN commands in Dockerfile and for the runtime environment
90+
91+
# Initialize pyenv, install Python version from .python-version, and set it globally for pyenv
92+
# Ensure .python-version was copied earlier and is readable
93+
RUN eval "$(pyenv init --path)" && \
94+
eval "$(pyenv init -)" && \
95+
eval "$(pyenv virtualenv-init -)" && \
96+
pyenv install --skip-existing $(cat ${HOMEDIR}/.python-version) && \
97+
pyenv global $(cat ${HOMEDIR}/.python-version) && \
98+
pyenv rehash
3999

40100
ENV NODE_ENV=production
41101

42-
# Needed to avoid the error "fatal: detected dubious ownership in repository at '/home/typedai'" when running git commands
43-
# as the application files are owned by the root user so an agent (which runs as the typedai user) can't modify them.
44-
RUN git config --global --add safe.directory /home/typedai
102+
# Needed to avoid "fatal: detected dubious ownership in repository"
103+
# This applies to /home/typedai because it's mounted from the host and owned by host's user in many cases
104+
RUN git config --global --add safe.directory ${HOMEDIR}
105+
# If your /workspace is also a git repo and you run git commands there:
106+
# RUN git config --global --add safe.directory /workspace
45107

46-
# In the frontend package.json the `ng serve` needs the arg --host 0.0.0.0 for it to be available from the host machine
47108
EXPOSE 4200
48109
EXPOSE 3000
49110
CMD ["./bin/cmd-script"]
50-

README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,21 @@ Included are capable software engineering agents, which have assisted building t
3636
- OpenTelemetry based observability
3737
- Leverages the extensive Python AI ecosystem through executing Python scripts/packages
3838

39+
## CLI Usage
40+
41+
TypedAI provides powerful command-line tools for automation and development workflows:
42+
43+
```bash
44+
# Quick examples using the ai wrapper script
45+
ai query "What test frameworks does this repository use?"
46+
ai code "Add error handling to the user authentication function"
47+
ai research "Latest developments in large language models"
48+
```
49+
50+
The `ai` script runs locally while `aid` runs in Docker for isolation. Both provide access to all CLI agents including the specialized `codeAgent` for autonomous code editing tasks.
51+
52+
For comprehensive CLI documentation, see the [CLI Usage Guide](https://typedai.dev/cli-usage/).
53+
3954
## Autonomous agents
4055

4156
- Reasoning/planning inspired from Google's [Self-Discover](https://arxiv.org/abs/2402.03620) and other papers

bin/ai-sdk-versions.ts

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
import * as fs from 'fs/promises'; // Use promises version for async/await
2+
import * as path from 'path';
3+
4+
// Official provider packages are at https://github.com/vercel/ai/tree/main/packages
5+
6+
// Define a basic type for the structure of package.json we care about
7+
interface PackageJson {
8+
dependencies?: {
9+
[key: string]: string;
10+
};
11+
// We don't need devDependencies, peerDependencies etc. for this task,
12+
// but you could add them here if needed.
13+
}
14+
15+
/**
16+
* Analyzes package.json files under node_modules/@ai-sdk/
17+
* to find the versions of @ai-sdk/provider and @ai-sdk/provider-utils
18+
* in their dependencies.
19+
*/
20+
async function analyzeAiSdkDependencies(): Promise<void> {
21+
const nodeModulesPath = path.join(process.cwd(), 'node_modules');
22+
const aiSdkDir = path.join(nodeModulesPath, '@ai-sdk');
23+
24+
console.log(`--- Analyzing dependencies under ${aiSdkDir} ---`);
25+
console.log(`(Ensure you are running this from your project's root directory)`);
26+
console.log('--------------------------------------------------\n');
27+
28+
29+
try {
30+
// Check if the base node_modules/@ai-sdk directory exists
31+
try {
32+
await fs.access(aiSdkDir);
33+
} catch (error: any) {
34+
if (error.code === 'ENOENT') {
35+
console.error(`Error: Directory not found: ${aiSdkDir}`);
36+
console.error("Please ensure you are running this script from your project's root directory and have installed your @ai-sdk packages.");
37+
} else {
38+
console.error(`An unexpected error occurred checking directory ${aiSdkDir}: ${error.message}`);
39+
}
40+
return; // Exit the function if the directory isn't found or accessible
41+
}
42+
43+
// Read the list of entries (files/directories) within @ai-sdk
44+
const entries = await fs.readdir(aiSdkDir);
45+
46+
let providerVersion;
47+
let providerUtilVersion;
48+
49+
// Process each entry found in the @ai-sdk directory
50+
for (const entryName of entries) {
51+
if(entryName === 'ui-utils' || entryName === 'react') continue;
52+
const packageJsonPath = path.join(aiSdkDir, entryName, 'package.json');
53+
54+
if (entryName === 'provider' || entryName === 'provider-utils') {
55+
const fileContent = await fs.readFile(packageJsonPath, 'utf8');
56+
const packageJson: any = JSON.parse(fileContent);
57+
if(entryName === 'provider-utils') {
58+
providerUtilVersion = packageJson.version
59+
}
60+
if(entryName === 'provider') {
61+
providerVersion = packageJson.version
62+
}
63+
continue;
64+
}
65+
66+
console.log(`--- ${entryName} ---`);
67+
68+
try {
69+
// Check if the entry is likely a directory by trying to access its package.json
70+
// This implicitly handles non-directories or directories without package.json
71+
await fs.access(packageJsonPath, fs.constants.R_OK); // Check if file exists and is readable
72+
73+
// Read and parse the package.json file
74+
const fileContent = await fs.readFile(packageJsonPath, 'utf8');
75+
const packageJson: PackageJson = JSON.parse(fileContent);
76+
77+
const dependencies = packageJson.dependencies;
78+
79+
// Check if the dependencies block exists and is an object
80+
if (dependencies && typeof dependencies === 'object') {
81+
const providerVersion = dependencies['@ai-sdk/provider'];
82+
const providerUtilsVersion = dependencies['@ai-sdk/provider-utils'];
83+
84+
if (providerVersion !== undefined) {
85+
console.log(` @ai-sdk/provider: ${providerVersion}`);
86+
} else {
87+
console.log(` @ai-sdk/provider: Not found in dependencies`);
88+
}
89+
90+
if (providerUtilsVersion !== undefined) {
91+
console.log(` @ai-sdk/provider-utils: ${providerUtilsVersion}`);
92+
} else {
93+
console.log(` @ai-sdk/provider-utils: Not found in dependencies`);
94+
}
95+
} else {
96+
console.log(' No "dependencies" block found in package.json');
97+
}
98+
99+
} catch (error: any) {
100+
// Handle errors specific to processing one package.json file
101+
if (error.code === 'ENOENT') {
102+
// File not found (most likely because entryName wasn't a directory with a package.json)
103+
console.warn(` Warning: No package.json found or accessible at ${packageJsonPath}`);
104+
} else if (error instanceof SyntaxError) {
105+
// JSON parsing error
106+
console.warn(` Warning: Invalid JSON in ${packageJsonPath}: ${error.message}`);
107+
} else {
108+
// Other potential errors like permissions issues
109+
console.error(` Error processing package.json for ${entryName}: ${error.message}`);
110+
}
111+
}
112+
console.log(''); // Add a blank line for separation between packages
113+
}
114+
115+
console.log();
116+
console.log('Provider version: ', providerVersion);
117+
console.log('Provider util version: ', providerUtilVersion);
118+
console.log();
119+
120+
console.log('--- Analysis Complete ---');
121+
122+
} catch (error: any) {
123+
// Handle errors during the initial directory read or other unexpected issues
124+
console.error(`An unexpected error occurred during analysis: ${error.message}`);
125+
}
126+
}
127+
128+
// Execute the function
129+
analyzeAiSdkDependencies().catch(console.error);

0 commit comments

Comments
 (0)