agentsdotmd 1.1.2 → 1.1.3

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.
@@ -50,9 +50,7 @@ cli
50
50
 
51
51
  try {
52
52
  const contents = await Promise.all(promises)
53
- const header = `<!-- This file is auto-generated by the agentsdotmd CLI from your package.json script.
54
- Do not edit this file directly. To add custom instructions, create a local file ./MY_AGENTS.md
55
- and add it to your agentsdotmd command in package.json. -->\n\n`
53
+ const header = `<!-- This AGENTS.md file is generated. Look for an agents.md package.json script to see what files to update instead. -->\n\n`
56
54
  const content = header + contents.join('\n') + '\n'
57
55
  fs.writeFileSync('AGENTS.md', content)
58
56
  console.log(`AGENTS.md generated successfully with ${files.length} file(s)`)
package/changelog.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # changelog
2
2
 
3
+ ## 1.1.3
4
+
5
+ ### Patch Changes
6
+
7
+ - vitest.md instructions update
8
+
3
9
  ## 1.1.2
4
10
 
5
11
  ### Patch Changes
package/dedent.md ADDED
@@ -0,0 +1,16 @@
1
+ ## dedent
2
+
3
+ when creating long strings in functions use dedent so that we can indent the string content and make it more readable
4
+
5
+ for example:
6
+
7
+ ```ts
8
+ import dedent from 'string-dedent'
9
+
10
+ const content = dedent`
11
+ some content
12
+ ```
13
+
14
+ IMPORTANT: notice that i have at start and end a new line. this is required when using string-dedent. Also notice npm package `string-dedent` instead of `dedent`.
15
+
16
+ When creating code snippets alias dedent to variables like html or javascript so that I get syntax highlight in my editor: `const html = dedent`
package/fly.md CHANGED
@@ -4,6 +4,8 @@ fly is a deployment platform. some packages use it to deploy the website. you ca
4
4
 
5
5
  usually there are 2 fly apps for each package, one staging environment and one production. these are 2 different apps at 2 different urls, you can target the right app usually by using `pnpm fly:preview` or `pnpm fly:prod`. sometimes there is only `pnpm fly` and you can use that instead. These scripts will append the right --app argument to work on the right fly app.
6
6
 
7
+ Never deploy with fly yourself. ask the user to do it
8
+
7
9
  ## reading logs
8
10
 
9
11
  you can read fly apps logs using `pnpm fly:preview logs --no-tail | tail -n 100`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentsdotmd",
3
- "version": "1.1.2",
3
+ "version": "1.1.3",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "index.js",
package/prisma.md CHANGED
@@ -49,10 +49,10 @@ this simply means to always include a check in prisma queries to make sure that
49
49
 
50
50
  ```typescript
51
51
  const resource = await prisma.resource.findFirst({
52
- where: { resourceId, parentResource: { users: { some: { userId } } } },
53
- })
52
+ where: { resourceId, parentResource: { users: { some: { userId } } } },
53
+ });
54
54
  if (!resource) {
55
- throw new AppError(`cannot find resource`)
55
+ throw new AppError(`cannot find resource`);
56
56
  }
57
57
  ```
58
58
 
@@ -81,4 +81,24 @@ if (!user.subscription) {
81
81
  JSON.stringify({ message: `user has no subscription` }),
82
82
  )
83
83
  }
84
- ````
84
+ ````
85
+
86
+ ## foreign key constraints
87
+
88
+ sometimes you will get errors like "Invalid `upsert()` invocation: Foreign key constraint violated on the constraint: `filed1_filed2_fkey`". This can be caused by the following issue
89
+
90
+ - a field that has a relation to table X is being passed a value where no table X exists for that id. You can fix the issue by making sure that the table exists before doing the create or upsert
91
+ - With upsert, even if the create branch is valid, the update branch can violate the FK.
92
+
93
+ ```ts
94
+ await prisma.child.upsert({
95
+ where: { id: 1 },
96
+ create: {
97
+ parent: { connect: { id: 1 } },
98
+ },
99
+ update: {
100
+ parent: { connect: { id: 9999 } }, // no such parent
101
+ },
102
+ });
103
+ ```
104
+ -
package/react.md CHANGED
@@ -37,3 +37,15 @@
37
37
  - non component code should be put in the src/lib folder.
38
38
 
39
39
  - hooks should be put in the src/hooks.tsx file. do not create a new file for each new hook. also notice that you should never create custom hooks, only do it if asked for.
40
+
41
+ ## zustand
42
+
43
+ zustand is the preferred way to created global React state. put it in files like state.ts or x-state.ts where x is something that describe a portion of app state in case of multiple global states or multiple apps
44
+
45
+ - minimize number of props. do not use props if you can use zustand state instead. the app has global zustand state that lets you get a piece of state down from the component tree by using something like `useStore(x => x.something)` or `useLoaderData<typeof loader>()` or even useRouteLoaderData if you are deep in the react component tree
46
+
47
+ - do not consider local state truthful when interacting with server. when interacting with the server with rpc or api calls never use state from the render function as input for the api call. this state can easily become stale or not get updated in the closure context. instead prefer using zustand `useStore.getState().stateValue`. notice that useLoaderData or useParams should be fine in this case.
48
+
49
+ - NEVER add zustand state setter methods. instead use useStore.setState to set state. For example never add a method `setVariable` in the state type. Instead call `setState` directly
50
+
51
+ - zustand already merges new partial state with the previous state. NEVER DO `useStore.setState({ ...useStore.getInitialState(), ... })` unless for resetting state
@@ -0,0 +1,84 @@
1
+ # Retryable, Resumable, Idempotent Tasks — Summary
2
+
3
+ ## Problem
4
+
5
+ - Long-running tasks (e.g.,Notion sync, AI chat, website generation) take minutes.
6
+ - Keeping a single connection open → network error probability grows with time.
7
+ - Tasks also do outbound network calls → compound failure surface.
8
+ - Risk of duplicate/concurrent runs corrupting state.
9
+
10
+ ## Goals
11
+
12
+ - **Resumable**: continue from last checkpoint after failures.
13
+ - **Retryable**: safe to retry automatically.
14
+ - **Idempotent**: side effects via upserts/deterministic writes.
15
+ - **Single-flight**: prevent concurrent execution per task.
16
+
17
+ ## Core Principles
18
+
19
+ - Checkpoint progress (cursor/step) frequently.
20
+ - Deterministic ordering (e.g., pages list) so “skip until cursor” is correct.
21
+ - At-least-once safe semantics: dedupe by (task_id, sequence/event_id).
22
+ - Small, explicit payload carrying resume info on every retry.
23
+
24
+ ## Client vs Server State
25
+
26
+ ### Client-held (prefer for AI chat / interactive flows)
27
+
28
+ - Client persists: messages[], partial assistant text, last_event_seq.
29
+ - Request includes: task_id (resume_token), messages[], partial_assistant, last_event_seq.
30
+ - Server is stateless: reconstructs from request; uses model “prefill” to resume (verify model support; Anthropic supports; OpenAI may vary).
31
+ - Benefit: fewer server-side moving parts. Cost: model compatibility + client must track emitted events.
32
+
33
+ ### Server-held (required for background jobs / fixed retry bodies, e.g., QStash)
34
+
35
+ - DB state per task: {task_id, step, cursor (last_synced_page_id), checksum, updated_at}.
36
+ - Resume by skipping to cursor using deterministic ordering.
37
+ - Needed when infrastructure cannot modify retry payloads.
38
+
39
+ ## Concurrency Control
40
+
41
+ - Single-flight/lease per task_id:
42
+ - Acquire lease with TTL + heartbeats.
43
+ - If a retry arrives while running: attach to existing run or reject with retry-after.
44
+ - Release lease on completion or expiry.
45
+
46
+ ## API Shape (minimal)
47
+
48
+ - POST /tasks/start → {task_id, optional cursor}
49
+ - POST /tasks/resume → body must include:
50
+ - task_id (resume_token)
51
+ - last_cursor (e.g., last_synced_page_id)
52
+ - last_event_seq (for stream dedupe)
53
+ - client_state if server is stateless (e.g., messages[])
54
+ - GET /tasks/status?task_id=… → {step, cursor, percent}
55
+
56
+ ## Retry Strategy
57
+
58
+ - Exponential backoff + jitter; cap total time.
59
+ - Persist checkpoint before/after each substantial step.
60
+ - Retries always include last_cursor + last_event_seq.
61
+ - Treat transport and model/API timeouts as retriable; invalid input as terminal.
62
+
63
+ ## Event Replay (AI chat)
64
+
65
+ - All server events carry monotonically increasing seq.
66
+ - Client sends last_event_seq on resume; server suppresses ≤ seq to avoid duplicates.
67
+
68
+ ## Sync Pattern
69
+
70
+ - Pre-compute deterministic ordered page list.
71
+ - Cursor = last_synced_page_id.
72
+ - On resume: “skip-until-cursor” then continue.
73
+ - Idempotent writes (upsert by external_id).
74
+
75
+ ## Spice Flow Notes
76
+
77
+ - Current “retry same body” is insufficient; add ability to override body on retry.
78
+ - Temporary workaround: client-managed loop that updates last_cursor and re-posts.
79
+
80
+ ## What to Verify
81
+
82
+ - Model prefill/continuation support for chosen LLM.
83
+ - Lease/lock implementation (row-level lock or key-value lease with TTL).
84
+ - Observability: log task_id, step, cursor, retry_count, lease_owner.
package/shadcn.md CHANGED
@@ -16,4 +16,8 @@
16
16
 
17
17
  this project uses shadcn components placed in the website/src/components/ui folder. never add a new shadcn component yourself by writing code. instead use the shadcn cli installed locally.
18
18
 
19
- try to reuse these available components when you can, for example for buttons, tooltips, scroll areas, etc.
19
+ try to reuse these available components when you can, for example for buttons, tooltips, scroll areas, etc.
20
+
21
+ ## reusing shadcn components
22
+
23
+ when creating a new React component or adding jsx before creating your own buttons or other elements first check the files inside `src/components/ui` and `src/components` to see what is already available. So you can reuse things like Button and Tooltip components instead of creating your own.
package/stripe.md CHANGED
@@ -7,6 +7,31 @@ the Stripe billing portal is used to
7
7
  - send user to payment to create a sub via `stripe.checkout.sessions.create`
8
8
  - let user change plan, cancel or change payment method ("manage subscription") via `stripe.billingPortal.sessions.create`
9
9
 
10
+ ## customerId
11
+
12
+ every time you are about to do a call to `checkout.sessions.create` make sure that we create the Stripe customer first. So that we do not get duplicate Stripe customers for different subscriptions:
13
+
14
+ ```ts
15
+
16
+ let customerId = org.stripeCustomerId
17
+
18
+ if (!customerId) {
19
+ const customer = await stripe.customers.create({
20
+ email: org.email || undefined,
21
+ name: org.name || undefined,
22
+ })
23
+
24
+ customerId = customer.id
25
+
26
+ await prisma.org.update({
27
+ where: { id: orgId },
28
+ data: { stripeCustomerId: customerId },
29
+ })
30
+ }
31
+
32
+ await stripe.checkout.sessions.create({ customer: customerId, ... })
33
+ ```
34
+
10
35
  ## subscriptions
11
36
 
12
37
  a subscription is active if state is in
@@ -14,6 +39,18 @@ a subscription is active if state is in
14
39
  - trialing
15
40
  - active
16
41
 
42
+ ```ts
43
+ await prisma.subscription.findFirst({
44
+ where: {
45
+ orgId: orgId,
46
+ status: {
47
+ in: ["active", "trialing"],
48
+ },
49
+ // ...
50
+ },
51
+ });
52
+ ```
53
+
17
54
  a subscription can be reactivated if state is NOT in
18
55
 
19
56
  - canceled
@@ -21,6 +58,3 @@ a subscription can be reactivated if state is NOT in
21
58
  - unpaid
22
59
 
23
60
  > If sub is in any of these states the user will not be able to use the billing portal to reactivate it. Meaning we should treat a subscription in these states as completely missing. Forcing the user to create a new one instead of shoging the "manage subscription" button that redirects the user to the billing portal. BUT customer id must be preserved, reusing previous sub customerId in `stripe.billingPortal.sessions.create({ customer: prevCustomerId })`
24
-
25
-
26
- ##
package/tailwind.md CHANGED
@@ -11,3 +11,5 @@ for margin, padding, gaps, widths and heights it is preferable to use multiples
11
11
  4 is equal to 16px which is the default font size of the page. this way every spacing is a multiple of the height and width of a default letter.
12
12
 
13
13
  user interfaces are mostly text so using the letter width and height as a base unit makes it easier to reason about the layout and sizes.
14
+
15
+ use grow instead of flex-1.
package/typescript.md CHANGED
@@ -6,6 +6,10 @@
6
6
 
7
7
  - always add the {} block body in arrow functions: arrow functions should never be written as `onClick={(x) => setState('')}`. NEVER. instead you should ALWAYS write `onClick={() => {setState('')}}`. this way it's easy to add new statements in the arrow function without refactoring it.
8
8
 
9
+ - in array operations .map, .filter, .reduce and .flatMap are preferred over .forEach and for of loops. For example prefer doing `.push(...array.map(x => x.items))` over mutating array variables inside for loops. Always think of how to turn for loops into expressions using .map, .filter or .flatMap if you ever are about to write a for loop.
10
+
11
+ - if you encounter typescript errors like "undefined | T is not assignable to T" after .filter(Boolean) operations: use a guarded function instead of Boolean: `.filter(isTruthy)`. implemented as `function isTruthy<T>(value: T): value is NonNullable<T> { return Boolean(value) }`
12
+
9
13
  - minimize useless comments: do not add useless comments if the code is self descriptive. only add comments if requested or if this was a change that i asked for, meaning it is not obvious code and needs some inline documentation. if a comment is required because the part of the code was result of difficult back and forth with me, keep it very short.
10
14
 
11
15
  - ALWAYS add all information encapsulated in my prompt to comments: when my prompt is super detailed and in depth, all this information should be added to comments in your code. this is because if the prompt is very detailed it must be the fruit of a lot of research. all this information would be lost if you don't put it in the code. next LLM calls would misinterpret the code and miss context.
@@ -28,7 +32,7 @@
28
32
 
29
33
  - when creating urls from a path and a base url, prefer using `new URL(path, baseUrl).toString()` instead of normal string interpolation. use type-safe react-router `href` or spiceflow `this.safePath` (available inside routes) if possible
30
34
 
31
- - for node built-in imports, never import singular names. instead do `import fs from 'node:fs'`, same for path, os, etc.
35
+ - for node built-in imports, never import singular exported names. instead do `import fs from 'node:fs'`, same for path, os, etc.
32
36
 
33
37
  - NEVER start the development server with pnpm dev yourself. there is no reason to do so, even with &
34
38
 
package/vitest.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  do not write new test files unless asked. do not write tests if there is not already a test or describe block for that function or module.
4
4
 
5
+ if the inputs for the tests is an array of repetitive fields and long content, generate this input data programmatically instead of hardcoding everything. only hardcode the important parts and generate other repetitive fields in a .map or .reduce
6
+
5
7
  tests should validate complex and non-obvious logic. if a test looks like a placeholder, do not add it.
6
8
 
7
9
  use vitest to run tests. tests should be run from the current package directory and not root. try using the test script instead of vitest directly. additional vitest flags can be added at the end, like --run to disable watch mode or -u to update snapshots.