traits 0.4.0 → 0.5.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.
Files changed (106) hide show
  1. package/Assessment.ts +14 -0
  2. package/LICENSE +203 -0
  3. package/Source.ts +13 -0
  4. package/Trait.ts +51 -0
  5. package/TraitConflict.ts +52 -0
  6. package/TraitDerivation.ts +137 -0
  7. package/TraitEvaluation.ts +69 -0
  8. package/TraitStore.ts +88 -0
  9. package/TraitsConfig.ts +57 -0
  10. package/TraitsContext.ts +11 -0
  11. package/_util/Approval.ts +59 -0
  12. package/_util/Git.ts +25 -0
  13. package/_util/TraitsConfigProvider.ts +22 -0
  14. package/_util/TraitsTelemetry.ts +20 -0
  15. package/_util/words.ts +555 -0
  16. package/commands/init.ts +73 -0
  17. package/dist/Assessment.d.ts +12 -0
  18. package/dist/Assessment.d.ts.map +1 -0
  19. package/dist/Assessment.js +12 -0
  20. package/dist/Assessment.js.map +1 -0
  21. package/dist/Source.d.ts +21 -0
  22. package/dist/Source.d.ts.map +1 -0
  23. package/dist/Source.js +10 -0
  24. package/dist/Source.js.map +1 -0
  25. package/dist/Trait.d.ts +12 -0
  26. package/dist/Trait.d.ts.map +1 -0
  27. package/dist/Trait.js +44 -0
  28. package/dist/Trait.js.map +1 -0
  29. package/dist/TraitConflict.d.ts +56 -0
  30. package/dist/TraitConflict.d.ts.map +1 -0
  31. package/dist/TraitConflict.js +47 -0
  32. package/dist/TraitConflict.js.map +1 -0
  33. package/dist/TraitDerivation.d.ts +99 -0
  34. package/dist/TraitDerivation.d.ts.map +1 -0
  35. package/dist/TraitDerivation.js +109 -0
  36. package/dist/TraitDerivation.js.map +1 -0
  37. package/dist/TraitEvaluation.d.ts +68 -0
  38. package/dist/TraitEvaluation.d.ts.map +1 -0
  39. package/dist/TraitEvaluation.js +61 -0
  40. package/dist/TraitEvaluation.js.map +1 -0
  41. package/dist/TraitStore.d.ts +17 -0
  42. package/dist/TraitStore.d.ts.map +1 -0
  43. package/dist/TraitStore.js +57 -0
  44. package/dist/TraitStore.js.map +1 -0
  45. package/dist/TraitsConfig.d.ts +14 -0
  46. package/dist/TraitsConfig.d.ts.map +1 -0
  47. package/dist/TraitsConfig.js +40 -0
  48. package/dist/TraitsConfig.js.map +1 -0
  49. package/dist/TraitsContext.d.ts +11 -0
  50. package/dist/TraitsContext.d.ts.map +1 -0
  51. package/dist/TraitsContext.js +4 -0
  52. package/dist/TraitsContext.js.map +1 -0
  53. package/dist/_util/Approval.d.ts +28 -0
  54. package/dist/_util/Approval.d.ts.map +1 -0
  55. package/dist/_util/Approval.js +48 -0
  56. package/dist/_util/Approval.js.map +1 -0
  57. package/dist/_util/Git.d.ts +15 -0
  58. package/dist/_util/Git.d.ts.map +1 -0
  59. package/dist/_util/Git.js +17 -0
  60. package/dist/_util/Git.js.map +1 -0
  61. package/dist/_util/TraitsConfigProvider.d.ts +3 -0
  62. package/dist/_util/TraitsConfigProvider.d.ts.map +1 -0
  63. package/dist/_util/TraitsConfigProvider.js +17 -0
  64. package/dist/_util/TraitsConfigProvider.js.map +1 -0
  65. package/dist/_util/TraitsTelemetry.d.ts +3 -0
  66. package/dist/_util/TraitsTelemetry.d.ts.map +1 -0
  67. package/dist/_util/TraitsTelemetry.js +12 -0
  68. package/dist/_util/TraitsTelemetry.js.map +1 -0
  69. package/dist/_util/words.d.ts +2 -0
  70. package/dist/_util/words.d.ts.map +1 -0
  71. package/dist/_util/words.js +556 -0
  72. package/dist/_util/words.js.map +1 -0
  73. package/dist/commands/init.d.ts +4 -0
  74. package/dist/commands/init.d.ts.map +1 -0
  75. package/dist/commands/init.js +67 -0
  76. package/dist/commands/init.js.map +1 -0
  77. package/dist/index.d.ts +10 -0
  78. package/dist/index.d.ts.map +1 -0
  79. package/dist/index.js +10 -0
  80. package/dist/index.js.map +1 -0
  81. package/dist/main.d.ts +3 -0
  82. package/dist/main.d.ts.map +1 -0
  83. package/dist/main.js +73 -0
  84. package/dist/main.js.map +1 -0
  85. package/dist/package.json +53 -0
  86. package/dist/toolkit/CheckTraits.d.ts +79 -0
  87. package/dist/toolkit/CheckTraits.d.ts.map +1 -0
  88. package/dist/toolkit/CheckTraits.js +110 -0
  89. package/dist/toolkit/CheckTraits.js.map +1 -0
  90. package/dist/toolkit/DeriveTrait.d.ts +108 -0
  91. package/dist/toolkit/DeriveTrait.d.ts.map +1 -0
  92. package/dist/toolkit/DeriveTrait.js +54 -0
  93. package/dist/toolkit/DeriveTrait.js.map +1 -0
  94. package/dist/toolkit/toolkit.d.ts +3 -0
  95. package/dist/toolkit/toolkit.d.ts.map +1 -0
  96. package/dist/toolkit/toolkit.js +6 -0
  97. package/dist/toolkit/toolkit.js.map +1 -0
  98. package/index.ts +9 -0
  99. package/main.ts +113 -0
  100. package/package.json +46 -0
  101. package/skills/traits/SKILL.md +307 -0
  102. package/toolkit/CheckTraits.ts +150 -0
  103. package/toolkit/DeriveTrait.ts +59 -0
  104. package/toolkit/toolkit.ts +9 -0
  105. 1289345811335-0.8567837113514543/lib/traits.js +0 -662
  106. 1289345811335-0.8567837113514543/package.json +0 -7
package/dist/main.js ADDED
@@ -0,0 +1,73 @@
1
+ #!/usr/bin/env node
2
+ import { NodeRuntime, NodeServices } from "@effect/platform-node";
3
+ import { Effect, Layer, Logger, Option, Schema as S, String } from "effect";
4
+ import { McpProtocol, McpServer } from "effect/ai";
5
+ import { Command, Flag } from "effect/cli";
6
+ import { FetchHttpClient } from "effect/http";
7
+ import * as TraitsConfigProvider from "./_util/TraitsConfigProvider.js";
8
+ import * as TraitsTelemetry from "./_util/TraitsTelemetry.js";
9
+ import { init } from "./commands/init.js";
10
+ import PackageJson from "./package.json" with { type: "json" };
11
+ import { toolkit } from "./toolkit/toolkit.js";
12
+ import * as TraitsConfig from "./TraitsConfig.js";
13
+ import * as TraitStore from "./TraitStore.js";
14
+ Command.make("traits", {
15
+ otlpEndpoint: Flag.String("otlp-endpoint").pipe(Flag.withSchema(S.URLFromString.check(S.makeFilter((url) => url.protocol === "http:" || url.protocol === "https:" || "Use an HTTP(S) collector base URL."))), Flag.withDescription("Export traces and logs as OTLP/HTTP JSON to this collector base URL (for example, http://127.0.0.1:4318). Disabled when omitted."), Flag.optional)
16
+ }).pipe(Command.withDescription("Run the traits MCP server over stdio"), Command.withHandler((params) => McpServer.layerStdio({
17
+ name: "traits",
18
+ version: PackageJson.version,
19
+ protocols: [McpProtocol.v2025_11_25],
20
+ instructions: String.stripMargin(`
21
+ | Traits are durable, reusable coding preferences stored as .agents/traits/<three_words-uuid>.md in the working directory.
22
+ | The full filename stem is the trait ID; use it in tool calls, for example rose_karate_frog-<uuid>.
23
+ | Before completing a response to a user correction, coding preference, or approved alternative idiom, check whether it expresses a reusable rule.
24
+ | Treat multi-turn exchanges as a whole: asking about a better idiom and then approving it can establish a preference without saying "always" or "trait".
25
+ | Err on the side of proposing a concise trait unless you have read an existing trait that clearly covers the exact rule and its scope.
26
+ | If coverage is uncertain, propose the rule rather than silently assuming a broad trait covers it. If clearer wording is needed, propose a clarification.
27
+ | Call the mutation tool with the drafted proposal first, leaving approved unset. Do not ask separately beforehand: native clients get an approval form.
28
+ | derive_trait uses native MCP forms when usable, or returns ApprovalRequired with the complete proposal for that same interactive question flow.
29
+ | Only on ApprovalRequired, show the full message using the interactive question tool: Save, Revise, Skip, plus its automatic free-text option. Use plain text only if that UI is unavailable.
30
+ | Retry an identical approved proposal with approved: true; do not assert approval for changed wording or targets. Native forms still apply on supported clients.
31
+ | RevisionRequired contains feedback to incorporate before requesting approval again; Declined means stop without writing.
32
+ | Revise without actionable feedback requires an immediate interactive question asking what to change; never guess or treat it as Save.
33
+ | Keep a revision pending across related audits or follow-up tasks. Complete that work, then return to the proposal unless explicitly cancelled.
34
+ | Show the complete revised proposal and obtain fresh approval before saving; a findings summary does not resolve a pending revision.
35
+ | Approval to edit code alone is not approval to persist a trait. Make the requested edit, but also propose the reusable rule before your final response.
36
+ | Also act on explicit requests to remember a convention. Skip one-off requirements, transient facts, and preferences already covered.
37
+ | Read existing trait files before drafting. Keep each trait concise and independently applicable, preserving scope and exceptions.
38
+ | Call derive_trait with the drafted body as proposedTrait. It saves only distinct rules; Covered means reuse an existing trait.
39
+ | A single clarification candidate is selected automatically and shown for approval; supply a complete replacement preserving the existing rule.
40
+ | Multiple candidates return Clarification entries without writing: refine the proposal or clarify intent. Do not supply a target ID.
41
+ | After fallback approval, retry with the same proposedTrait and approved: true; Updated preserves the selected existing ID.
42
+ | Every derive_trait response is one tagged TraitDerivation outcome. Created returns the saved trait and ID; Updated and Resolved return saved replacements.
43
+ | Covered and Clarification return existing traits without writing. Inconclusive returns relationship findings and blocks all writes.
44
+ | Each inconclusive outcome's findings distinguish conflict from inconclusive via reason; clarify ambiguity before retrying.
45
+ | Confirmed conflicts enter reconciliation inside derive_trait, selecting only the conflicting originals for an explicit replacement approval.
46
+ | Approval must cover affected IDs/bodies, removals, the proposal, and generated reconciliation. Nothing is replaced silently.
47
+ | After approval, reconciliation gives the proposal precedence in direct conflicts, saves generated replacements, then removes the conflicting originals.
48
+ | Resolved returns saved replacement bodies and IDs. Review them and check relevant code; do not derive the same proposal again.
49
+ | After generating or changing TypeScript files, call check_traits on those files.
50
+ | check_traits accepts include as file paths or glob strings, for example include: ["traits/**/*.ts"]. Overlapping matches are deduplicated.
51
+ | Restrict assessments to project-owned source and relevant authored configuration/docs. Prefer an explicit project-file manifest for whole-project audits.
52
+ | Never submit dependency/reference code, generated build output or lockfiles, Git metadata, secrets, .env files, credentials, or binary assets for assessment.
53
+ | Unmatched patterns select nothing. Built-in exclusions cover dependencies, Git metadata, and nested worktrees; configure project-specific filenames or native glob patterns through TraitsConfig.excludes.
54
+ | After saving or resolving a trait, check the relevant TypeScript files explicitly; creation does not run that review for you.
55
+ | Omit traitIds for all traits; use specific IDs for focused follow-ups. Before committing or opening a PR, review the changed TypeScript files.
56
+ | Checks read current full files in 200-line chunks, not Git diffs. A finding's startLine locates a chunk, not an exact violation.
57
+ | Each finding includes assessment.classification and probabilities: inconclusive is unresolved context, not a confirmed violation. Probabilities are not calibrated guarantees.
58
+ | Take responsibility for trait compliance whenever a violation is discovered, through tool findings or your own inspection.
59
+ | Inspect each finding against its trait, scope, exceptions, and surrounding source; confirmed violations must be fixed without waiting for another user request.
60
+ | Make minimal behavior-preserving edits to the implementation, not to the trait merely to silence a finding. Do not stop at a findings summary.
61
+ | Rerun check_traits on every corrected file, then run relevant formatting, type, and behavior checks; repeat for remaining confirmed violations.
62
+ | Triage raw findings against the exact rule, scope, exceptions, and source before reporting or editing. Do not blindly change correct code.
63
+ | Routine user summaries should report confirmed issues, meaningful unresolved uncertainty, operational failures, and blockers requiring a decision.
64
+ | Do not repeat rejected, irrelevant false positives as caveats or make them sound actionable. Keep raw results available in tool output and telemetry.
65
+ | Discuss a rejected finding when the user requests audit details or it reveals a new material reliability problem; explain why it was rejected.
66
+ | Never suppress actionable findings based only on confidence, assume a finding is false because similar ones were wrong, or claim an automated clean pass when raw findings remain.
67
+ | If a fix requires a behavior change, broader authorization, or an ambiguous interpretation, ask a focused question and report the blocker.
68
+ | Do not claim compliance while confirmed violations remain. Report model errors as incomplete reviews, not passes.
69
+ | An empty result only means no failures for the selected files and traits; empty selections or an empty store perform no assessments.
70
+ | On mutation errors, inspect the store before retrying: writes and removals are not transactional, and retries may duplicate saved traits.
71
+ `)
72
+ }).pipe(Layer.provide(toolkit.pipe(Layer.provide(TraitStore.layerFileSystem(".agents/traits")), Layer.provide(TraitsConfig.layer), Layer.provideMerge(McpServer.McpServer.layer))), Layer.launch, Effect.withSpan("traits.server"), Effect.provide(TraitsTelemetry.layer(Option.getOrUndefined(params.otlpEndpoint)).pipe(Layer.provideMerge(TraitsConfigProvider.layer), Layer.provideMerge(FetchHttpClient.layer))))), Command.withSubcommands([init]), Command.run({ version: PackageJson.version }), Effect.provide(NodeServices.layer), Effect.tapCause(Effect.logError), Effect.provideService(Logger.LogToStderr, true), NodeRuntime.runMain({ disableErrorReporting: true }));
73
+ //# sourceMappingURL=main.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../main.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "traits",
3
+ "version": "0.5.0",
4
+ "license": "Apache-2.0",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/crosshatch/traits.git",
8
+ "directory": "traits"
9
+ },
10
+ "bin": {
11
+ "traits": "./dist/main.js"
12
+ },
13
+ "files": [
14
+ "*.ts",
15
+ "!vite.config.ts",
16
+ "_util/**/*.ts",
17
+ "commands/**/*.ts",
18
+ "skills/**/*.md",
19
+ "toolkit/**/*.ts",
20
+ "dist/package.json",
21
+ "dist/**/*.js",
22
+ "dist/**/*.js.map",
23
+ "dist/**/*.d.ts",
24
+ "dist/**/*.d.ts.map",
25
+ "!dist/vite.config.*"
26
+ ],
27
+ "type": "module",
28
+ "exports": {
29
+ "./package.json": "./package.json",
30
+ ".": "./index.ts",
31
+ "./*": "./*.ts",
32
+ "./_util/*": null,
33
+ "./index": null
34
+ },
35
+ "publishConfig": {
36
+ "exports": {
37
+ "./package.json": "./package.json",
38
+ ".": "./dist/index.js",
39
+ "./*": "./dist/*.js",
40
+ "./_util/*": null,
41
+ "./index": null
42
+ },
43
+ "access": "public"
44
+ },
45
+ "devDependencies": {
46
+ "@effect/platform-node": "catalog:",
47
+ "effect": "catalog:"
48
+ },
49
+ "peerDependencies": {
50
+ "@effect/platform-node": "catalog:",
51
+ "effect": "catalog:"
52
+ }
53
+ }
@@ -0,0 +1,79 @@
1
+ import { FileSystem, Path, Schema as S } from "effect";
2
+ import { AiError, DecisionModel, Tool, Toolkit } from "effect/ai";
3
+ import { ChildProcessSpawner } from "effect/process";
4
+ import { TraitsContext } from "../TraitsContext.ts";
5
+ import { TraitStore } from "../TraitStore.ts";
6
+ export declare const CheckTraits: Tool.Tool<"check_traits", {
7
+ readonly parameters: S.Struct<{
8
+ readonly include: S.$Array<S.String>;
9
+ readonly traitIds: S.optional<S.$Array<S.brand<S.String, "traits/Trait">>>;
10
+ }>;
11
+ readonly success: S.$Array<S.Struct<{
12
+ readonly trait: S.Struct<{
13
+ readonly id: S.brand<S.String, "traits/Trait">;
14
+ readonly body: S.String;
15
+ }>;
16
+ readonly source: S.Struct<{
17
+ readonly text: S.String;
18
+ readonly location: S.optional<S.TaggedUnion<{
19
+ readonly File: S.TaggedStruct<"File", {
20
+ readonly path: S.String;
21
+ readonly startLine: S.Int;
22
+ }>;
23
+ readonly Generated: S.TaggedStruct<"Generated", {}>;
24
+ }>>;
25
+ }>;
26
+ readonly assessment: S.Struct<{
27
+ readonly classification: S.Literals<readonly ["compliant", "violation", "not-applicable", "inconclusive"]>;
28
+ readonly probabilities: S.Struct<{
29
+ readonly compliant: S.Finite;
30
+ readonly violation: S.Finite;
31
+ readonly "not-applicable": S.Finite;
32
+ readonly inconclusive: S.Finite;
33
+ }>;
34
+ }>;
35
+ }>>;
36
+ readonly failure: S.Union<readonly [typeof AiError.AiError, S.TaggedStruct<"PlatformError", {
37
+ readonly message: S.String;
38
+ }>]>;
39
+ readonly failureMode: "error";
40
+ }, ChildProcessSpawner.ChildProcessSpawner | DecisionModel.DecisionModel | FileSystem.FileSystem | Path.Path | TraitStore | TraitsContext>;
41
+ export declare const toolkit: Toolkit.Toolkit<{
42
+ readonly check_traits: Tool.Tool<"check_traits", {
43
+ readonly parameters: S.Struct<{
44
+ readonly include: S.$Array<S.String>;
45
+ readonly traitIds: S.optional<S.$Array<S.brand<S.String, "traits/Trait">>>;
46
+ }>;
47
+ readonly success: S.$Array<S.Struct<{
48
+ readonly trait: S.Struct<{
49
+ readonly id: S.brand<S.String, "traits/Trait">;
50
+ readonly body: S.String;
51
+ }>;
52
+ readonly source: S.Struct<{
53
+ readonly text: S.String;
54
+ readonly location: S.optional<S.TaggedUnion<{
55
+ readonly File: S.TaggedStruct<"File", {
56
+ readonly path: S.String;
57
+ readonly startLine: S.Int;
58
+ }>;
59
+ readonly Generated: S.TaggedStruct<"Generated", {}>;
60
+ }>>;
61
+ }>;
62
+ readonly assessment: S.Struct<{
63
+ readonly classification: S.Literals<readonly ["compliant", "violation", "not-applicable", "inconclusive"]>;
64
+ readonly probabilities: S.Struct<{
65
+ readonly compliant: S.Finite;
66
+ readonly violation: S.Finite;
67
+ readonly "not-applicable": S.Finite;
68
+ readonly inconclusive: S.Finite;
69
+ }>;
70
+ }>;
71
+ }>>;
72
+ readonly failure: S.Union<readonly [typeof AiError.AiError, S.TaggedStruct<"PlatformError", {
73
+ readonly message: S.String;
74
+ }>]>;
75
+ readonly failureMode: "error";
76
+ }, ChildProcessSpawner.ChildProcessSpawner | DecisionModel.DecisionModel | FileSystem.FileSystem | Path.Path | TraitStore | TraitsContext>;
77
+ }>;
78
+ export declare const layer: import("effect/Layer").Layer<Tool.Handler<"check_traits">, never, never>;
79
+ //# sourceMappingURL=CheckTraits.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CheckTraits.d.ts","sourceRoot":"","sources":["../../toolkit/CheckTraits.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,UAAU,EAAE,IAAI,EAAuB,MAAM,IAAI,CAAC,EAAkB,MAAM,QAAQ,CAAA;AAC1G,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACjE,OAAO,EAAgB,mBAAmB,EAAE,MAAM,gBAAgB,CAAA;AAKlE,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,EAAE,UAAU,EAAmB,MAAM,kBAAkB,CAAA;AAE9D,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;0IAmDY,CAAA;AAEpC,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAA4B,CAAA;AAEhD,eAAO,MAAM,KAAK,0EAoFhB,CAAA"}
@@ -0,0 +1,110 @@
1
+ import { Array, Effect, FileSystem, Path, pipe, PlatformError, Schema as S, Stream, String } from "effect";
2
+ import { AiError, DecisionModel, Tool, Toolkit } from "effect/ai";
3
+ import { ChildProcess, ChildProcessSpawner } from "effect/process";
4
+ import { Source, SourceLocation } from "../Source.js";
5
+ import { TraitId } from "../Trait.js";
6
+ import { evaluate, requiresReview, TraitEvaluation } from "../TraitEvaluation.js";
7
+ import { TraitsContext } from "../TraitsContext.js";
8
+ import { TraitStore, TraitStoreError } from "../TraitStore.js";
9
+ export const CheckTraits = Tool.make("check_traits", {
10
+ description: String.stripMargin(`
11
+ | Use after generating or editing TypeScript files, after saving or resolving a relevant trait, and before committing or opening a PR.
12
+ | Assess only project-owned source files and relevant authored configuration or documentation. Do not audit third-party or generated code.
13
+ | For a whole-project review, prefer an explicit project-file manifest rather than a filesystem-wide glob.
14
+ | Never submit secrets, .env files, credentials, binary assets, generated lockfiles, dependency trees, or reference repositories for assessment.
15
+ | Supply include as TypeScript file paths or glob patterns relevant to the work, relative to the MCP working directory or absolute.
16
+ | Globs are expanded and overlapping matches are checked once. Directories are not reviewed as files; use patterns such as traits/**/*.ts.
17
+ | Built-in exclusions cover dependency trees, Git metadata, and nested worktrees. Configure project-specific exclusions through TraitsConfig.excludes.
18
+ | Configured exclusions are filenames or native filesystem glob patterns, resolved beside traits.ts. Use directory/** to exclude a subtree; bare directories are not expanded.
19
+ | Git-ignored files are excluded by default, with ignore rules refreshed on every call. Untracked files do not need to be added to Git to be evaluated. Tracked files remain eligible even if ignore rules match them. Set excludeGitignored: false in traits.ts to disable this filter; explicit excludes still apply. Git failures fail the check.
20
+ | All entries follow native glob syntax, including escaping filenames with glob characters. No custom directory expansion or literal-path classification is applied.
21
+ | Reads current full file contents, including unstaged edits, and checks each 200-line chunk against the selected traits in parallel.
22
+ | Omit traitIds to check all stored traits; supply trait ids for a focused check of one or more traits. Unknown IDs fail the call.
23
+ | Returns findings with the trait, source text, absolute path, 1-based chunk startLine, and assessment classification and probabilities.
24
+ | Classification distinguishes violation from inconclusive; probabilities are not calibrated guarantees. No exact offending lines are provided.
25
+ | Diagnose uncertainty using the full distribution, not the selected label alone; inspect source and trait before changing code.
26
+ | Act on the results: inspect every finding and automatically fix confirmed, applicable violations without waiting for a separate request.
27
+ | Make minimal behavior-preserving code changes, then rerun this tool on the corrected files and run relevant project checks.
28
+ | Repeat for remaining confirmed violations; returning a findings summary alone does not complete the review.
29
+ | Do not weaken a trait to make code pass or change correct code for an inapplicable or inconclusive finding.
30
+ | Triage each finding before reporting it. Routine summaries should surface confirmed issues, meaningful unresolved uncertainty, errors, and decision blockers.
31
+ | Do not distract the user with rejected, irrelevant false positives; retain raw results in tool output for audit and explain them when requested or materially significant.
32
+ | Do not hide actionable findings based only on probability/confidence or claim the automated check was clean when raw findings remain.
33
+ | Ask for clarification when a fix changes behavior or exceeds authorized scope.
34
+ | The tool diagnoses only; the calling agent is responsible for edits, verification, and reporting unresolved blockers.
35
+ | Unmatched patterns select no files. An empty result means no failures for this selection, not a repository-wide guarantee.
36
+ | Empty include/traitIds lists, no matched files, or an empty store check no pairs.
37
+ `),
38
+ parameters: S.Struct({
39
+ include: S.Array(S.String).annotate({
40
+ description: "Project-owned source, configuration, or documentation paths/globs, absolute or relative to the MCP working directory. Exclude third-party/generated files, secrets, and binaries. Overlapping matches are deduplicated; unmatched patterns select no files."
41
+ }),
42
+ traitIds: S.Array(TraitId).pipe(S.optional).annotate({
43
+ description: "Optional trait ids for a focused review. Omit for all stored traits; an empty array selects none."
44
+ })
45
+ }),
46
+ success: S.Array(TraitEvaluation),
47
+ failure: S.Union([AiError.AiError, TraitStoreError]),
48
+ dependencies: [
49
+ DecisionModel.DecisionModel,
50
+ TraitStore,
51
+ FileSystem.FileSystem,
52
+ Path.Path,
53
+ ChildProcessSpawner.ChildProcessSpawner,
54
+ TraitsContext
55
+ ]
56
+ })
57
+ .annotate(Tool.Title, "Check Traits")
58
+ .annotate(Tool.Readonly, true)
59
+ .annotate(Tool.Destructive, false);
60
+ export const toolkit = Toolkit.make(CheckTraits);
61
+ export const layer = toolkit.toLayer({
62
+ check_traits: Effect.fn("CheckTraits.check")(function* (params) {
63
+ const store = yield* TraitStore;
64
+ const context = yield* TraitsContext;
65
+ const fs = yield* FileSystem.FileSystem;
66
+ const path = yield* Path.Path;
67
+ const cwd = path.resolve();
68
+ const includedFiles = context.excludeGitignored
69
+ ? yield* Effect.scoped(Effect.gen(function* () {
70
+ const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
71
+ const process = yield* spawner.spawn(ChildProcess.make `git ls-files --cached --others --exclude-standard --full-name -z`.pipe(ChildProcess.setCwd(context.configRoot)));
72
+ const output = yield* process.stdout.pipe(Stream.decodeText(), Stream.mkString);
73
+ const exitCode = yield* process.exitCode;
74
+ if (exitCode !== 0) {
75
+ return yield* PlatformError.systemError({
76
+ _tag: "Unknown",
77
+ module: "ChildProcess",
78
+ method: "git ls-files",
79
+ description: `Process exited with code ${exitCode}`
80
+ });
81
+ }
82
+ return new Set(pipe(output, String.split("\0"), Array.filter(String.isNonEmpty), Array.map((file) => path.resolve(context.configRoot, file))));
83
+ }))
84
+ : undefined;
85
+ const traits = yield* params.traitIds === undefined
86
+ ? store.ls
87
+ : Effect.forEach(Array.dedupe(params.traitIds), store.get, { concurrency: "unbounded" });
88
+ const matches = yield* Effect.forEach(params.include, (pattern) => {
89
+ const absolute = path.isAbsolute(pattern) ? pattern : `${cwd}${path.sep}${pattern}`;
90
+ return fs.glob(absolute, {
91
+ root: context.configRoot,
92
+ exclude: context.excludes
93
+ });
94
+ }, { concurrency: "unbounded" });
95
+ const resolved = pipe(matches, Array.flatten, Array.map((file) => path.resolve(context.configRoot, file)), Array.dedupe);
96
+ const paths = yield* Effect.filter(includedFiles === undefined ? resolved : Array.filter(resolved, (file) => includedFiles.has(file)), (file) => fs.stat(file).pipe(Effect.map((info) => info.type === "File")), { concurrency: "unbounded" });
97
+ const results = yield* Effect.forEach(paths, Effect.fn("CheckTraits.file")(function* (file) {
98
+ const text = yield* fs.readFileString(file);
99
+ const chunks = Array.chunksOf(String.split(text, "\n"), 200);
100
+ const sources = Array.map(chunks, (lines, index) => Source.make({
101
+ text: Array.join(lines, "\n"),
102
+ location: SourceLocation.cases.File.make({ path: file, startLine: index * 200 + 1 })
103
+ }));
104
+ const results = yield* Effect.forEach(sources, (source) => Effect.forEach(traits, (trait) => evaluate(trait, source), { concurrency: "unbounded" }), { concurrency: "unbounded" });
105
+ return pipe(results, Array.flatten, Array.filter(requiresReview));
106
+ }), { concurrency: "unbounded" });
107
+ return Array.flatten(results);
108
+ })
109
+ });
110
+ //# sourceMappingURL=CheckTraits.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CheckTraits.js","sourceRoot":"","sources":["../../toolkit/CheckTraits.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,108 @@
1
+ import { Schema as S } from "effect";
2
+ import { AiError, DecisionModel, LanguageModel, McpSchema, Tool, Toolkit } from "effect/ai";
3
+ import { TraitsContext } from "../TraitsContext.ts";
4
+ import { TraitStore } from "../TraitStore.ts";
5
+ export declare const DeriveTrait: Tool.Tool<"derive_trait", {
6
+ readonly parameters: S.Struct<{
7
+ readonly proposedTrait: S.String;
8
+ readonly approved: S.optional<S.Boolean>;
9
+ }>;
10
+ readonly success: S.toTaggedUnion<"_tag", readonly [S.TaggedStruct<"Created", {
11
+ readonly trait: S.Struct<{
12
+ readonly id: S.brand<S.String, "traits/Trait">;
13
+ readonly body: S.String;
14
+ }>;
15
+ }>, S.TaggedStruct<"Covered", {
16
+ readonly traits: S.$Array<S.Struct<{
17
+ readonly id: S.brand<S.String, "traits/Trait">;
18
+ readonly body: S.String;
19
+ }>>;
20
+ }>, S.TaggedStruct<"Clarification", {
21
+ readonly traits: S.$Array<S.Struct<{
22
+ readonly id: S.brand<S.String, "traits/Trait">;
23
+ readonly body: S.String;
24
+ }>>;
25
+ readonly proposedTrait: S.String;
26
+ }>, S.TaggedStruct<"Inconclusive", {
27
+ readonly findings: S.$Array<S.TaggedStruct<"Fail", {
28
+ readonly existing: S.Struct<{
29
+ readonly id: S.brand<S.String, "traits/Trait">;
30
+ readonly body: S.String;
31
+ }>;
32
+ readonly proposed: S.String;
33
+ readonly reason: S.Literals<readonly ["conflict", "inconclusive"]>;
34
+ }>>;
35
+ }>, S.TaggedStruct<"Updated", {
36
+ readonly trait: S.Struct<{
37
+ readonly id: S.brand<S.String, "traits/Trait">;
38
+ readonly body: S.String;
39
+ }>;
40
+ }>, S.TaggedStruct<"Resolved", {
41
+ readonly traits: S.$Array<S.Struct<{
42
+ readonly id: S.brand<S.String, "traits/Trait">;
43
+ readonly body: S.String;
44
+ }>>;
45
+ }>, S.TaggedStruct<"ApprovalRequired", {
46
+ readonly message: S.String;
47
+ }>, S.TaggedStruct<"RevisionRequired", {
48
+ readonly feedback: S.String;
49
+ }>, S.TaggedStruct<"Declined", {}>]>;
50
+ readonly failure: S.Union<readonly [typeof AiError.AiError, S.TaggedStruct<"PlatformError", {
51
+ readonly message: S.String;
52
+ }>, typeof McpSchema.ElicitationDeclined]>;
53
+ readonly failureMode: "error";
54
+ }, DecisionModel.DecisionModel | LanguageModel.LanguageModel | TraitStore | TraitsContext>;
55
+ export declare const toolkit: Toolkit.Toolkit<{
56
+ readonly derive_trait: Tool.Tool<"derive_trait", {
57
+ readonly parameters: S.Struct<{
58
+ readonly proposedTrait: S.String;
59
+ readonly approved: S.optional<S.Boolean>;
60
+ }>;
61
+ readonly success: S.toTaggedUnion<"_tag", readonly [S.TaggedStruct<"Created", {
62
+ readonly trait: S.Struct<{
63
+ readonly id: S.brand<S.String, "traits/Trait">;
64
+ readonly body: S.String;
65
+ }>;
66
+ }>, S.TaggedStruct<"Covered", {
67
+ readonly traits: S.$Array<S.Struct<{
68
+ readonly id: S.brand<S.String, "traits/Trait">;
69
+ readonly body: S.String;
70
+ }>>;
71
+ }>, S.TaggedStruct<"Clarification", {
72
+ readonly traits: S.$Array<S.Struct<{
73
+ readonly id: S.brand<S.String, "traits/Trait">;
74
+ readonly body: S.String;
75
+ }>>;
76
+ readonly proposedTrait: S.String;
77
+ }>, S.TaggedStruct<"Inconclusive", {
78
+ readonly findings: S.$Array<S.TaggedStruct<"Fail", {
79
+ readonly existing: S.Struct<{
80
+ readonly id: S.brand<S.String, "traits/Trait">;
81
+ readonly body: S.String;
82
+ }>;
83
+ readonly proposed: S.String;
84
+ readonly reason: S.Literals<readonly ["conflict", "inconclusive"]>;
85
+ }>>;
86
+ }>, S.TaggedStruct<"Updated", {
87
+ readonly trait: S.Struct<{
88
+ readonly id: S.brand<S.String, "traits/Trait">;
89
+ readonly body: S.String;
90
+ }>;
91
+ }>, S.TaggedStruct<"Resolved", {
92
+ readonly traits: S.$Array<S.Struct<{
93
+ readonly id: S.brand<S.String, "traits/Trait">;
94
+ readonly body: S.String;
95
+ }>>;
96
+ }>, S.TaggedStruct<"ApprovalRequired", {
97
+ readonly message: S.String;
98
+ }>, S.TaggedStruct<"RevisionRequired", {
99
+ readonly feedback: S.String;
100
+ }>, S.TaggedStruct<"Declined", {}>]>;
101
+ readonly failure: S.Union<readonly [typeof AiError.AiError, S.TaggedStruct<"PlatformError", {
102
+ readonly message: S.String;
103
+ }>, typeof McpSchema.ElicitationDeclined]>;
104
+ readonly failureMode: "error";
105
+ }, DecisionModel.DecisionModel | LanguageModel.LanguageModel | TraitStore | TraitsContext>;
106
+ }>;
107
+ export declare const layer: import("effect/Layer").Layer<Tool.Handler<"derive_trait">, never, never>;
108
+ //# sourceMappingURL=DeriveTrait.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DeriveTrait.d.ts","sourceRoot":"","sources":["../../toolkit/DeriveTrait.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC,EAAU,MAAM,QAAQ,CAAA;AAC5C,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAG3F,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,EAAE,UAAU,EAAmB,MAAM,kBAAkB,CAAA;AAE9D,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;0FA6CW,CAAA;AAEnC,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAA4B,CAAA;AAEhD,eAAO,MAAM,KAAK,0EAEhB,CAAA"}
@@ -0,0 +1,54 @@
1
+ import { Schema as S, String } from "effect";
2
+ import { AiError, DecisionModel, LanguageModel, McpSchema, Tool, Toolkit } from "effect/ai";
3
+ import { derive, TraitDerivation } from "../TraitDerivation.js";
4
+ import { TraitsContext } from "../TraitsContext.js";
5
+ import { TraitStore, TraitStoreError } from "../TraitStore.js";
6
+ export const DeriveTrait = Tool.make("derive_trait", {
7
+ description: String.stripMargin(`
8
+ | Use after a user correction, reusable coding preference, or explicit request to remember a convention.
9
+ | Recognize preferences across turns, including approval of a suggested alternative idiom; do not require the words "always" or "trait".
10
+ | Err on the side of proposing a rule unless an existing trait clearly covers its exact scope. Call this tool with the draft first; do not ask separately beforehand.
11
+ | An explicit request to save the rule counts as approval; approval to change code alone does not.
12
+ | Native clients receive an approval form. ApprovalRequired means use the interactive question tool with Save, Revise, and Skip choices and its free-text option.
13
+ | Include the full returned message. Retry with the exact same body and target and approved: true only after Save; revise and request approval again for changed text.
14
+ | RevisionRequired contains feedback; revise and resubmit. Declined means stop without writing. Never retry automatically after a decline.
15
+ | If Revise supplies no concrete feedback, ask for revision details with the interactive question UI and free text. Do not guess or set approved: true.
16
+ | Keep the proposal pending through related work and return to it afterward unless cancelled; obtain fresh approval of the complete revised body.
17
+ | First decide whether the feedback generalizes beyond the current task and inspect existing trait files for coverage.
18
+ | Supply a concise, standalone rule as proposedTrait, preserving its scope and exceptions; omit headings and unnecessary examples.
19
+ | Compare against all stored traits. Only a distinct proposal is saved as a new trait.
20
+ | Inconclusive returns relationship findings and blocks all writes; clarify ambiguity or revise the proposal before retrying.
21
+ | Confirmed conflicts enter reconciliation within this tool. Approval shows affected trait IDs/bodies, removals, the proposal, and replacement policy.
22
+ | Nothing is replaced before approval. After approval, generate compatible standalone replacements, save them, then delete only the conflicting originals.
23
+ | The proposal takes precedence only in direct conflicts; preserve unrelated requirements, scopes, and exceptions. Resolved returns saved replacements.
24
+ | Do not submit the same proposal again after Resolved: it is already incorporated. Inspect replacements and check relevant TypeScript files.
25
+ | Reconciliation is not transactional; on an error, inspect the store before retrying because some writes or removals may have completed.
26
+ | Covered returns the existing traits representing the proposal; reuse them without writing a duplicate.
27
+ | A single clarification candidate is selected automatically for approval; provide a complete replacement body preserving existing requirements and exceptions.
28
+ | Multiple clarification candidates return Clarification with those traits and the proposal without writing. Refine the proposal or clarify intent.
29
+ | The shared approval flow shows the existing and proposed bodies; ask in the client UI only if ApprovalRequired is returned.
30
+ | The tool rechecks all traits before updating, preserving the selected ID. Updated returns the saved trait.
31
+ | Never use approved: true for an unapproved replacement, and never resolve a mere clarification by deleting traits.
32
+ | Created returns the saved trait including its generated ID. Every response is one tagged TraitDerivation outcome, never a bare array or void.
33
+ | Then call check_traits on relevant TypeScript files, using returned trait IDs for focused reviews when appropriate.
34
+ `),
35
+ parameters: S.Struct({
36
+ proposedTrait: S.String.annotate({
37
+ description: "The complete reusable rule to save, including scope and exceptions, rather than raw conversation text."
38
+ }),
39
+ approved: S.Boolean.pipe(S.optional).annotate({
40
+ description: "Fallback approval for the exact proposal and automatically selected action shown to the user, including any existing trait being updated. Set true only after approval; native clients still receive a form. Does not bypass relationship checks."
41
+ })
42
+ }),
43
+ success: TraitDerivation,
44
+ failure: S.Union([AiError.AiError, TraitStoreError, McpSchema.ElicitationDeclined]),
45
+ dependencies: [DecisionModel.DecisionModel, LanguageModel.LanguageModel, TraitStore, TraitsContext]
46
+ })
47
+ .annotate(Tool.Title, "Derive Trait")
48
+ .annotate(Tool.Readonly, false)
49
+ .annotate(Tool.Destructive, true);
50
+ export const toolkit = Toolkit.make(DeriveTrait);
51
+ export const layer = toolkit.toLayer({
52
+ derive_trait: derive
53
+ });
54
+ //# sourceMappingURL=DeriveTrait.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DeriveTrait.js","sourceRoot":"","sources":["../../toolkit/DeriveTrait.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC5C,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAE3F,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAE9D,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE;IACnD,WAAW,EAAE,MAAM,CAAC,WAAW,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2B/B,CAAC;IACF,UAAU,EAAE,CAAC,CAAC,MAAM,CAAC;QACnB,aAAa,EAAE,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC;YAC/B,WAAW,EACT,wGAAwG;SAC3G,CAAC;QACF,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC;YAC5C,WAAW,EACT,mPAAmP;SACtP,CAAC;KACH,CAAC;IACF,OAAO,EAAE,eAAe;IACxB,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,eAAe,EAAE,SAAS,CAAC,mBAAmB,CAAC,CAAC;IACnF,YAAY,EAAE,CAAC,aAAa,CAAC,aAAa,EAAE,aAAa,CAAC,aAAa,EAAE,UAAU,EAAE,aAAa,CAAC;CACpG,CAAC;KACC,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,cAAc,CAAC;KACpC,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC;KAC9B,QAAQ,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,CAAA;AAEnC,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;AAEhD,MAAM,CAAC,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC;IACnC,YAAY,EAAE,MAAM;CACrB,CAAC,CAAA"}
@@ -0,0 +1,3 @@
1
+ import { Layer } from "effect";
2
+ export declare const toolkit: Layer.Layer<never, never, never>;
3
+ //# sourceMappingURL=toolkit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toolkit.d.ts","sourceRoot":"","sources":["../../toolkit/toolkit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AAM9B,eAAO,MAAM,OAAO,kCAEnB,CAAA"}
@@ -0,0 +1,6 @@
1
+ import { Layer } from "effect";
2
+ import { McpServer, Toolkit } from "effect/ai";
3
+ import * as CheckTraits from "./CheckTraits.js";
4
+ import * as DeriveTrait from "./DeriveTrait.js";
5
+ export const toolkit = McpServer.toolkit(Toolkit.merge(DeriveTrait.toolkit, CheckTraits.toolkit)).pipe(Layer.provide(Layer.mergeAll(DeriveTrait.layer, CheckTraits.layer)));
6
+ //# sourceMappingURL=toolkit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toolkit.js","sourceRoot":"","sources":["../../toolkit/toolkit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AAC9B,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAE9C,OAAO,KAAK,WAAW,MAAM,kBAAkB,CAAA;AAC/C,OAAO,KAAK,WAAW,MAAM,kBAAkB,CAAA;AAE/C,MAAM,CAAC,MAAM,OAAO,GAAG,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,OAAO,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CACpG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,WAAW,CAAC,KAAK,EAAE,WAAW,CAAC,KAAK,CAAC,CAAC,CACpE,CAAA"}
package/index.ts ADDED
@@ -0,0 +1,9 @@
1
+ export * as Assessment from "./Assessment.ts"
2
+ export * as Source from "./Source.ts"
3
+ export * as Trait from "./Trait.ts"
4
+ export * as TraitConflict from "./TraitConflict.ts"
5
+ export * as TraitDerivation from "./TraitDerivation.ts"
6
+ export * as TraitEvaluation from "./TraitEvaluation.ts"
7
+ export * from "./TraitsConfig.ts"
8
+ export * as TraitsContext from "./TraitsContext.ts"
9
+ export * as TraitStore from "./TraitStore.ts"