centy 0.0.21 → 0.0.22

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 (148) hide show
  1. package/bin/run.js +19 -2
  2. package/dist/commands/add/asset.d.ts +1 -0
  3. package/dist/commands/add/asset.d.ts.map +1 -1
  4. package/dist/commands/add/asset.js +14 -5
  5. package/dist/commands/add/asset.js.map +1 -1
  6. package/dist/commands/compact.d.ts.map +1 -1
  7. package/dist/commands/compact.js +9 -4
  8. package/dist/commands/compact.js.map +1 -1
  9. package/dist/commands/config.d.ts.map +1 -1
  10. package/dist/commands/config.js +9 -4
  11. package/dist/commands/config.js.map +1 -1
  12. package/dist/commands/create/doc.d.ts +1 -0
  13. package/dist/commands/create/doc.d.ts.map +1 -1
  14. package/dist/commands/create/doc.js +14 -5
  15. package/dist/commands/create/doc.js.map +1 -1
  16. package/dist/commands/create/issue.d.ts +1 -0
  17. package/dist/commands/create/issue.d.ts.map +1 -1
  18. package/dist/commands/create/issue.js +5 -2
  19. package/dist/commands/create/issue.js.map +1 -1
  20. package/dist/commands/create/pr.d.ts +1 -0
  21. package/dist/commands/create/pr.d.ts.map +1 -1
  22. package/dist/commands/create/pr.js +5 -1
  23. package/dist/commands/create/pr.js.map +1 -1
  24. package/dist/commands/delete/asset.d.ts +1 -0
  25. package/dist/commands/delete/asset.d.ts.map +1 -1
  26. package/dist/commands/delete/asset.js +14 -5
  27. package/dist/commands/delete/asset.js.map +1 -1
  28. package/dist/commands/delete/doc.d.ts +1 -0
  29. package/dist/commands/delete/doc.d.ts.map +1 -1
  30. package/dist/commands/delete/doc.js +14 -5
  31. package/dist/commands/delete/doc.js.map +1 -1
  32. package/dist/commands/delete/issue.d.ts +1 -0
  33. package/dist/commands/delete/issue.d.ts.map +1 -1
  34. package/dist/commands/delete/issue.js +14 -5
  35. package/dist/commands/delete/issue.js.map +1 -1
  36. package/dist/commands/delete/pr.d.ts +1 -0
  37. package/dist/commands/delete/pr.d.ts.map +1 -1
  38. package/dist/commands/delete/pr.js +14 -5
  39. package/dist/commands/delete/pr.js.map +1 -1
  40. package/dist/commands/get/asset.d.ts +1 -0
  41. package/dist/commands/get/asset.d.ts.map +1 -1
  42. package/dist/commands/get/asset.js +14 -5
  43. package/dist/commands/get/asset.js.map +1 -1
  44. package/dist/commands/get/doc.d.ts +2 -0
  45. package/dist/commands/get/doc.d.ts.map +1 -1
  46. package/dist/commands/get/doc.js +97 -17
  47. package/dist/commands/get/doc.js.map +1 -1
  48. package/dist/commands/get/issue.d.ts +1 -0
  49. package/dist/commands/get/issue.d.ts.map +1 -1
  50. package/dist/commands/get/issue.js +63 -27
  51. package/dist/commands/get/issue.js.map +1 -1
  52. package/dist/commands/get/pr.d.ts +2 -0
  53. package/dist/commands/get/pr.d.ts.map +1 -1
  54. package/dist/commands/get/pr.js +135 -40
  55. package/dist/commands/get/pr.js.map +1 -1
  56. package/dist/commands/list/assets.d.ts +1 -0
  57. package/dist/commands/list/assets.d.ts.map +1 -1
  58. package/dist/commands/list/assets.js +14 -5
  59. package/dist/commands/list/assets.js.map +1 -1
  60. package/dist/commands/list/docs.d.ts +1 -0
  61. package/dist/commands/list/docs.d.ts.map +1 -1
  62. package/dist/commands/list/docs.js +14 -5
  63. package/dist/commands/list/docs.js.map +1 -1
  64. package/dist/commands/list/issues.d.ts +1 -0
  65. package/dist/commands/list/issues.d.ts.map +1 -1
  66. package/dist/commands/list/issues.js +14 -5
  67. package/dist/commands/list/issues.js.map +1 -1
  68. package/dist/commands/list/prs.d.ts +1 -0
  69. package/dist/commands/list/prs.d.ts.map +1 -1
  70. package/dist/commands/list/prs.js +14 -5
  71. package/dist/commands/list/prs.js.map +1 -1
  72. package/dist/commands/manifest.d.ts.map +1 -1
  73. package/dist/commands/manifest.js +9 -4
  74. package/dist/commands/manifest.js.map +1 -1
  75. package/dist/commands/start.d.ts +2 -0
  76. package/dist/commands/start.d.ts.map +1 -1
  77. package/dist/commands/start.js +56 -2
  78. package/dist/commands/start.js.map +1 -1
  79. package/dist/commands/update/doc.d.ts +1 -0
  80. package/dist/commands/update/doc.d.ts.map +1 -1
  81. package/dist/commands/update/doc.js +14 -5
  82. package/dist/commands/update/doc.js.map +1 -1
  83. package/dist/commands/update/issue.d.ts +1 -0
  84. package/dist/commands/update/issue.d.ts.map +1 -1
  85. package/dist/commands/update/issue.js +14 -5
  86. package/dist/commands/update/issue.js.map +1 -1
  87. package/dist/commands/update/pr.d.ts +1 -0
  88. package/dist/commands/update/pr.d.ts.map +1 -1
  89. package/dist/commands/update/pr.js +14 -5
  90. package/dist/commands/update/pr.js.map +1 -1
  91. package/dist/commands/update.d.ts.map +1 -1
  92. package/dist/commands/update.js +9 -4
  93. package/dist/commands/update.js.map +1 -1
  94. package/dist/commands/version.d.ts.map +1 -1
  95. package/dist/commands/version.js +9 -4
  96. package/dist/commands/version.js.map +1 -1
  97. package/dist/daemon/daemon-get-docs-by-slug.d.ts +6 -0
  98. package/dist/daemon/daemon-get-docs-by-slug.d.ts.map +1 -0
  99. package/dist/daemon/daemon-get-docs-by-slug.js +17 -0
  100. package/dist/daemon/daemon-get-docs-by-slug.js.map +1 -0
  101. package/dist/daemon/daemon-get-prs-by-uuid.d.ts +6 -0
  102. package/dist/daemon/daemon-get-prs-by-uuid.d.ts.map +1 -0
  103. package/dist/daemon/daemon-get-prs-by-uuid.js +17 -0
  104. package/dist/daemon/daemon-get-prs-by-uuid.js.map +1 -0
  105. package/dist/daemon/load-proto.d.ts +3 -1
  106. package/dist/daemon/load-proto.d.ts.map +1 -1
  107. package/dist/daemon/load-proto.js.map +1 -1
  108. package/dist/daemon/types.d.ts +26 -0
  109. package/dist/daemon/types.d.ts.map +1 -1
  110. package/dist/flags/project-flag.d.ts +6 -0
  111. package/dist/flags/project-flag.d.ts.map +1 -0
  112. package/dist/flags/project-flag.js +9 -0
  113. package/dist/flags/project-flag.js.map +1 -0
  114. package/dist/lib/start/prompt-for-install.d.ts +13 -0
  115. package/dist/lib/start/prompt-for-install.d.ts.map +1 -0
  116. package/dist/lib/start/prompt-for-install.js +12 -0
  117. package/dist/lib/start/prompt-for-install.js.map +1 -0
  118. package/dist/utils/ask-yes-no.d.ts +10 -0
  119. package/dist/utils/ask-yes-no.d.ts.map +1 -0
  120. package/dist/utils/ask-yes-no.js +26 -0
  121. package/dist/utils/ask-yes-no.js.map +1 -0
  122. package/dist/utils/cross-project-search.d.ts +7 -0
  123. package/dist/utils/cross-project-search.d.ts.map +1 -0
  124. package/dist/utils/cross-project-search.js +7 -0
  125. package/dist/utils/cross-project-search.js.map +1 -0
  126. package/dist/utils/ensure-initialized.d.ts +10 -0
  127. package/dist/utils/ensure-initialized.d.ts.map +1 -0
  128. package/dist/utils/ensure-initialized.js +26 -0
  129. package/dist/utils/ensure-initialized.js.map +1 -0
  130. package/dist/utils/format-cross-project-hint.d.ts +9 -0
  131. package/dist/utils/format-cross-project-hint.d.ts.map +1 -0
  132. package/dist/utils/format-cross-project-hint.js +17 -0
  133. package/dist/utils/format-cross-project-hint.js.map +1 -0
  134. package/dist/utils/format-cross-project-json.d.ts +9 -0
  135. package/dist/utils/format-cross-project-json.d.ts.map +1 -0
  136. package/dist/utils/format-cross-project-json.js +16 -0
  137. package/dist/utils/format-cross-project-json.js.map +1 -0
  138. package/dist/utils/is-not-found-error.d.ts +5 -0
  139. package/dist/utils/is-not-found-error.d.ts.map +1 -0
  140. package/dist/utils/is-not-found-error.js +14 -0
  141. package/dist/utils/is-not-found-error.js.map +1 -0
  142. package/dist/utils/resolve-project-path.d.ts +17 -0
  143. package/dist/utils/resolve-project-path.d.ts.map +1 -0
  144. package/dist/utils/resolve-project-path.js +72 -0
  145. package/dist/utils/resolve-project-path.js.map +1 -0
  146. package/oclif.manifest.json +368 -188
  147. package/package.json +1 -1
  148. package/proto/centy.proto +272 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "centy",
3
- "version": "0.0.21",
3
+ "version": "0.0.22",
4
4
  "description": "CLI for managing project issues and docs via code in the .centy folder",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
package/proto/centy.proto CHANGED
@@ -57,6 +57,9 @@ service CentyDaemon {
57
57
  // Get a single doc by slug
58
58
  rpc GetDoc(GetDocRequest) returns (Doc);
59
59
 
60
+ // Get docs by slug across all tracked projects (global search)
61
+ rpc GetDocsBySlug(GetDocsBySlugRequest) returns (GetDocsBySlugResponse);
62
+
60
63
  // List all docs
61
64
  rpc ListDocs(ListDocsRequest) returns (ListDocsResponse);
62
65
 
@@ -125,6 +128,9 @@ service CentyDaemon {
125
128
  // Get a single PR by display number (human-readable number like 1, 2, 3)
126
129
  rpc GetPrByDisplayNumber(GetPrByDisplayNumberRequest) returns (PullRequest);
127
130
 
131
+ // Get PRs by UUID across all tracked projects (global search)
132
+ rpc GetPrsByUuid(GetPrsByUuidRequest) returns (GetPrsByUuidResponse);
133
+
128
134
  // List all PRs with optional filtering
129
135
  rpc ListPrs(ListPrsRequest) returns (ListPrsResponse);
130
136
 
@@ -167,6 +173,37 @@ service CentyDaemon {
167
173
 
168
174
  // Mark multiple issues as compacted
169
175
  rpc MarkIssuesCompacted(MarkIssuesCompactedRequest) returns (MarkIssuesCompactedResponse);
176
+
177
+ // ============ LLM Agent RPCs ============
178
+
179
+ // Spawn an LLM agent to work on an issue
180
+ rpc SpawnAgent(SpawnAgentRequest) returns (SpawnAgentResponse);
181
+
182
+ // Get current LLM work session for a project
183
+ rpc GetLlmWork(GetLlmWorkRequest) returns (GetLlmWorkResponse);
184
+
185
+ // Clear the active LLM work tracking
186
+ rpc ClearLlmWork(ClearLlmWorkRequest) returns (ClearLlmWorkResponse);
187
+
188
+ // Get local LLM configuration (config.local.json)
189
+ rpc GetLocalLlmConfig(GetLocalLlmConfigRequest) returns (GetLocalLlmConfigResponse);
190
+
191
+ // Update local LLM configuration
192
+ rpc UpdateLocalLlmConfig(UpdateLocalLlmConfigRequest) returns (UpdateLocalLlmConfigResponse);
193
+
194
+ // ============ Link RPCs ============
195
+
196
+ // Create a link between two entities (bidirectional)
197
+ rpc CreateLink(CreateLinkRequest) returns (CreateLinkResponse);
198
+
199
+ // Delete a link between two entities (bidirectional)
200
+ rpc DeleteLink(DeleteLinkRequest) returns (DeleteLinkResponse);
201
+
202
+ // List all links for an entity
203
+ rpc ListLinks(ListLinksRequest) returns (ListLinksResponse);
204
+
205
+ // Get all available link types (builtin + custom)
206
+ rpc GetAvailableLinkTypes(GetAvailableLinkTypesRequest) returns (GetAvailableLinkTypesResponse);
170
207
  }
171
208
 
172
209
  // ============ Init Messages ============
@@ -416,6 +453,7 @@ message Config {
416
453
  map<string, string> state_colors = 7; // State name → hex color (e.g., "open" → "#10b981")
417
454
  map<string, string> priority_colors = 8; // Priority level → hex color (e.g., "1" → "#ef4444")
418
455
  LlmConfig llm = 9; // LLM-related settings
456
+ repeated LinkTypeDefinition custom_link_types = 10; // Custom link types (in addition to built-in)
419
457
  }
420
458
 
421
459
  message CustomFieldDefinition {
@@ -432,6 +470,13 @@ message LlmConfig {
432
470
  bool allow_direct_edits = 3; // Allow LLM to directly edit issue files
433
471
  }
434
472
 
473
+ // Custom link type definition (for custom relationship types)
474
+ message LinkTypeDefinition {
475
+ string name = 1; // Link type name (e.g., "depends-on")
476
+ string inverse = 2; // Inverse link type (e.g., "dependency-of")
477
+ string description = 3; // Optional description
478
+ }
479
+
435
480
  message UpdateConfigRequest {
436
481
  string project_path = 1;
437
482
  Config config = 2;
@@ -477,6 +522,25 @@ message GetDocRequest {
477
522
  string slug = 2; // e.g., "getting-started"
478
523
  }
479
524
 
525
+ // ============ Global Doc Search Messages ============
526
+
527
+ message GetDocsBySlugRequest {
528
+ string slug = 1; // The slug to search for (kebab-case)
529
+ }
530
+
531
+ // A doc with its source project path
532
+ message DocWithProject {
533
+ Doc doc = 1;
534
+ string project_path = 2; // Absolute path to the project where this doc was found
535
+ string project_name = 3; // Human-readable project name (directory name)
536
+ }
537
+
538
+ message GetDocsBySlugResponse {
539
+ repeated DocWithProject docs = 1;
540
+ int32 total_count = 2;
541
+ repeated string errors = 3; // Non-fatal errors (e.g., projects that couldn't be accessed)
542
+ }
543
+
480
544
  message ListDocsRequest {
481
545
  string project_path = 1;
482
546
  }
@@ -603,7 +667,7 @@ message ListSharedAssetsRequest {
603
667
 
604
668
  // Returned by API (enriched with live data from disk)
605
669
  message ProjectInfo {
606
- string path = 1; // Absolute path to project
670
+ string path = 1; // Absolute path to project (use this for API calls)
607
671
  string first_accessed = 2; // ISO timestamp
608
672
  string last_accessed = 3; // ISO timestamp
609
673
  uint32 issue_count = 4; // Fetched live from .centy/issues/
@@ -612,6 +676,7 @@ message ProjectInfo {
612
676
  string name = 7; // Fetched live (directory name)
613
677
  bool is_favorite = 8; // User-marked favorite status
614
678
  bool is_archived = 9; // User-marked archived status
679
+ string display_path = 10; // Human-readable path with ~/ for home dir (use for display only)
615
680
  }
616
681
 
617
682
  message ListProjectsRequest {
@@ -815,6 +880,25 @@ message GetPrByDisplayNumberRequest {
815
880
  uint32 display_number = 2; // Human-readable number (1, 2, 3...)
816
881
  }
817
882
 
883
+ // ============ Global PR Search Messages ============
884
+
885
+ message GetPrsByUuidRequest {
886
+ string uuid = 1; // The UUID to search for (must be valid UUID format)
887
+ }
888
+
889
+ // A PR with its source project path
890
+ message PrWithProject {
891
+ PullRequest pr = 1;
892
+ string project_path = 2; // Absolute path to the project where this PR was found
893
+ string project_name = 3; // Human-readable project name (directory name)
894
+ }
895
+
896
+ message GetPrsByUuidResponse {
897
+ repeated PrWithProject prs = 1;
898
+ int32 total_count = 2;
899
+ repeated string errors = 3; // Non-fatal errors (e.g., projects that couldn't be accessed)
900
+ }
901
+
818
902
  message ListPrsRequest {
819
903
  string project_path = 1;
820
904
 
@@ -936,3 +1020,190 @@ message MarkIssuesCompactedResponse {
936
1020
  string error = 2;
937
1021
  uint32 marked_count = 3; // Number of issues successfully marked
938
1022
  }
1023
+
1024
+ // ============ LLM Agent Messages ============
1025
+
1026
+ // Predefined agent types
1027
+ enum AgentType {
1028
+ AGENT_TYPE_UNSPECIFIED = 0;
1029
+ AGENT_TYPE_CLAUDE = 1;
1030
+ AGENT_TYPE_GEMINI = 2;
1031
+ AGENT_TYPE_CODEX = 3;
1032
+ AGENT_TYPE_OPENCODE = 4;
1033
+ AGENT_TYPE_CUSTOM = 5;
1034
+ }
1035
+
1036
+ // Action types for LLM agents
1037
+ enum LlmAction {
1038
+ LLM_ACTION_UNSPECIFIED = 0;
1039
+ LLM_ACTION_PLAN = 1;
1040
+ LLM_ACTION_IMPLEMENT = 2;
1041
+ }
1042
+
1043
+ // Agent configuration (stored in config.local.json)
1044
+ message AgentConfig {
1045
+ AgentType agent_type = 1;
1046
+ string name = 2; // Display name (e.g., "claude", "my-agent")
1047
+ string command = 3; // CLI command (e.g., "claude", "/path/to/agent")
1048
+ repeated string default_args = 4; // Default arguments for the CLI
1049
+ string plan_template = 5; // Template name for "plan" action
1050
+ string implement_template = 6; // Template name for "implement" action
1051
+ }
1052
+
1053
+ // Local LLM configuration (config.local.json - not version controlled)
1054
+ message LocalLlmConfig {
1055
+ string default_agent = 1; // Name of default agent to use
1056
+ repeated AgentConfig agents = 2; // Available agents
1057
+ map<string, string> env_vars = 3; // Environment variables for agents
1058
+ }
1059
+
1060
+ // Request to spawn an LLM agent
1061
+ message SpawnAgentRequest {
1062
+ string project_path = 1;
1063
+ string issue_id = 2; // UUID or display number of issue to work on
1064
+ LlmAction action = 3; // "plan" or "implement"
1065
+ string agent_name = 4; // Agent to use (empty = default)
1066
+ repeated string extra_args = 5; // Additional CLI arguments
1067
+ }
1068
+
1069
+ message SpawnAgentResponse {
1070
+ bool success = 1;
1071
+ string error = 2;
1072
+ string agent_name = 3; // Which agent was spawned
1073
+ string issue_id = 4; // Resolved issue UUID
1074
+ uint32 display_number = 5; // Issue display number
1075
+ string prompt_preview = 6; // First 500 chars of generated prompt
1076
+ }
1077
+
1078
+ // Get active LLM work for a project
1079
+ message GetLlmWorkRequest {
1080
+ string project_path = 1;
1081
+ }
1082
+
1083
+ message LlmWorkSession {
1084
+ string issue_id = 1;
1085
+ uint32 display_number = 2;
1086
+ string issue_title = 3;
1087
+ string agent_name = 4;
1088
+ LlmAction action = 5;
1089
+ string started_at = 6; // ISO timestamp
1090
+ uint32 pid = 7; // Process ID (0 if unknown/exited)
1091
+ }
1092
+
1093
+ message GetLlmWorkResponse {
1094
+ bool has_active_work = 1;
1095
+ LlmWorkSession session = 2; // Current session (if any)
1096
+ }
1097
+
1098
+ // Clear active work tracking
1099
+ message ClearLlmWorkRequest {
1100
+ string project_path = 1;
1101
+ }
1102
+
1103
+ message ClearLlmWorkResponse {
1104
+ bool success = 1;
1105
+ string error = 2;
1106
+ }
1107
+
1108
+ // Get local LLM config
1109
+ message GetLocalLlmConfigRequest {
1110
+ string project_path = 1; // Empty = global config only
1111
+ }
1112
+
1113
+ message GetLocalLlmConfigResponse {
1114
+ LocalLlmConfig config = 1;
1115
+ bool has_project_config = 2;
1116
+ bool has_global_config = 3;
1117
+ }
1118
+
1119
+ // Update local LLM config
1120
+ message UpdateLocalLlmConfigRequest {
1121
+ string project_path = 1; // Empty = update global config
1122
+ LocalLlmConfig config = 2;
1123
+ }
1124
+
1125
+ message UpdateLocalLlmConfigResponse {
1126
+ bool success = 1;
1127
+ string error = 2;
1128
+ LocalLlmConfig config = 3;
1129
+ }
1130
+
1131
+ // ============ Link Messages ============
1132
+
1133
+ // Target entity type for links
1134
+ enum LinkTargetType {
1135
+ LINK_TARGET_TYPE_UNSPECIFIED = 0;
1136
+ LINK_TARGET_TYPE_ISSUE = 1;
1137
+ LINK_TARGET_TYPE_DOC = 2;
1138
+ LINK_TARGET_TYPE_PR = 3;
1139
+ }
1140
+
1141
+ // A link between two entities
1142
+ message Link {
1143
+ string target_id = 1; // Target entity ID (UUID for issues/PRs, slug for docs)
1144
+ LinkTargetType target_type = 2; // Type of the target entity
1145
+ string link_type = 3; // Relationship type (e.g., "blocks", "parent-of")
1146
+ string created_at = 4; // ISO timestamp when link was created
1147
+ }
1148
+
1149
+ // Create a link between two entities (bidirectional - also creates inverse)
1150
+ message CreateLinkRequest {
1151
+ string project_path = 1;
1152
+ string source_id = 2; // Source entity ID
1153
+ LinkTargetType source_type = 3; // Source entity type
1154
+ string target_id = 4; // Target entity ID
1155
+ LinkTargetType target_type = 5; // Target entity type
1156
+ string link_type = 6; // Link type (e.g., "blocks")
1157
+ }
1158
+
1159
+ message CreateLinkResponse {
1160
+ bool success = 1;
1161
+ string error = 2;
1162
+ Link created_link = 3; // The forward link that was created
1163
+ Link inverse_link = 4; // The inverse link that was created
1164
+ }
1165
+
1166
+ // Delete a link between two entities (also deletes inverse)
1167
+ message DeleteLinkRequest {
1168
+ string project_path = 1;
1169
+ string source_id = 2; // Source entity ID
1170
+ LinkTargetType source_type = 3; // Source entity type
1171
+ string target_id = 4; // Target entity ID
1172
+ LinkTargetType target_type = 5; // Target entity type
1173
+ string link_type = 6; // Optional: specific link type to delete (empty = all links between entities)
1174
+ }
1175
+
1176
+ message DeleteLinkResponse {
1177
+ bool success = 1;
1178
+ string error = 2;
1179
+ uint32 deleted_count = 3; // Number of links deleted (including inverse)
1180
+ }
1181
+
1182
+ // List all links for an entity
1183
+ message ListLinksRequest {
1184
+ string project_path = 1;
1185
+ string entity_id = 2; // Entity ID to list links for
1186
+ LinkTargetType entity_type = 3; // Entity type
1187
+ }
1188
+
1189
+ message ListLinksResponse {
1190
+ repeated Link links = 1;
1191
+ int32 total_count = 2;
1192
+ }
1193
+
1194
+ // Get all available link types (builtin + custom)
1195
+ message GetAvailableLinkTypesRequest {
1196
+ string project_path = 1;
1197
+ }
1198
+
1199
+ // Information about a link type
1200
+ message LinkTypeInfo {
1201
+ string name = 1; // Link type name (e.g., "blocks")
1202
+ string inverse = 2; // Inverse link type (e.g., "blocked-by")
1203
+ string description = 3; // Optional description
1204
+ bool is_builtin = 4; // Whether this is a built-in type
1205
+ }
1206
+
1207
+ message GetAvailableLinkTypesResponse {
1208
+ repeated LinkTypeInfo link_types = 1;
1209
+ }