phewsh 0.15.68 → 0.15.70

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/phewsh.js CHANGED
@@ -112,6 +112,7 @@ const COMMANDS = {
112
112
  work: () => require('../commands/work')(),
113
113
  remember: () => require('../commands/remember')(),
114
114
  task: () => require('../commands/task')(),
115
+ dispatch: () => require('../commands/task')(),
115
116
  pack: () => require('../commands/pack')(),
116
117
  hook: () => require('../commands/hook')(),
117
118
  welcome: () => require('../commands/welcome')(),
@@ -163,6 +164,7 @@ function showHelp() {
163
164
  console.log(` ${cyan('shim')} ${g('Guaranteed launch banner — phewsh prints status before each tool')}`);
164
165
  console.log(` ${cyan('pack')} ${g('Opt-in workflow packs (Karpathy guidelines, GSD…) — attributed, reversible')}`);
165
166
  console.log(` ${cyan('task')} ${g('Shared tasks — request, claim, and ship teammate work via branch + PR')}
167
+ ${cyan('dispatch')} ${g('Friendly verb over task: dispatch "<title>" to request, <id>|next to claim')}
166
168
  ${cyan('receipts')} ${g('Proof trail — what agents actually did, with evidence')}`);
167
169
  console.log(` ${cyan('remember')} ${g('Jot a decision to .intent/decisions.md — every tool inherits it')}`);
168
170
  console.log(` ${cyan('outcomes')} ${g('Decision record — what was kept, reverted, or failed')}`);
package/commands/task.js CHANGED
@@ -142,6 +142,33 @@ async function listTasks(config) {
142
142
  console.log(`\n ${g('Claim one:')} ${w('phewsh task claim <id>')}\n`);
143
143
  }
144
144
 
145
+ async function inviteTeammate(config, email) {
146
+ if (!email || !email.includes('@')) throw new Error('Usage: phewsh task invite <email>');
147
+ const project = await loadProject(config);
148
+ if (project.user_id !== config.supabaseUserId) throw new Error('Only the project owner can invite (Phase 2).');
149
+ await supa.insert('project_invites', {
150
+ project_id: project.id, email, invited_by: config.supabaseUserId,
151
+ }, config.supabaseAccessToken);
152
+ console.log(`\n ${green('✓')} Invited ${w(email)} to ${w(project.name)}`);
153
+ console.log(` ${g('They join with')} ${w('phewsh task join')} ${g('(CLI) or the Join banner on phewsh.com/intent/dashboard')}\n`);
154
+ }
155
+
156
+ async function joinProjects(config) {
157
+ // RLS also shows an owner their own outbound invites — only accept ours.
158
+ const invites = (await supa.select('project_invites',
159
+ 'accepted_at=is.null&select=id,project_id,email,created_at', config.supabaseAccessToken))
160
+ .filter((inv) => inv.email?.toLowerCase() === (config.email || '').toLowerCase());
161
+ if (!invites.length) {
162
+ console.log(`\n ${g('No pending invites for your account.')}\n`);
163
+ return;
164
+ }
165
+ for (const inv of invites) {
166
+ await supa.rpc('accept_project_invite', { invite_id: inv.id }, config.supabaseAccessToken);
167
+ console.log(`\n ${green('✓')} Joined project ${w(inv.project_id)}`);
168
+ }
169
+ console.log(` ${g('See its tasks from the project repo:')} ${w('phewsh task')}\n`);
170
+ }
171
+
145
172
  async function newTask(config, title) {
146
173
  if (!title) throw new Error('Usage: phewsh task new "<title>"');
147
174
  const project = await loadProject(config);
@@ -166,7 +193,13 @@ async function claimTask(config, idArg, viaFlag) {
166
193
  throw new Error('`gh` is not installed or not authenticated — needed to open the PR. Run `gh auth login`.');
167
194
  }
168
195
 
169
- // Resolve a short id prefix to the full task id.
196
+ // `claim next` = the oldest open task; otherwise resolve a short id prefix.
197
+ if (idArg === 'next') {
198
+ const open = await supa.select('tasks',
199
+ `project_id=eq.${project.id}&status=eq.open&select=id&order=created_at.asc&limit=1`, config.supabaseAccessToken);
200
+ if (!open.length) throw new Error('No open tasks to claim.');
201
+ idArg = open[0].id;
202
+ }
170
203
  const candidates = await supa.select('tasks',
171
204
  `project_id=eq.${project.id}&id=like.${idArg}*&select=*`, config.supabaseAccessToken)
172
205
  .catch(() => []);
@@ -239,8 +272,18 @@ async function claimTask(config, idArg, viaFlag) {
239
272
  console.log(` ${g('Clean up later:')} ${w(`git worktree remove ${worktree}`)}\n`);
240
273
  }
241
274
 
275
+ // `phewsh dispatch` is the friendly verb over the same machinery — no second
276
+ // architecture. Bare = list; an id prefix = claim; anything else = new task.
277
+ function dispatchToTaskArgs(args) {
278
+ const positional = args.filter((a, i) => !a.startsWith('--') && !(i > 0 && args[i - 1].startsWith('--')));
279
+ if (!positional.length) return ['list'];
280
+ if (positional.length === 1 && (positional[0] === 'next' || /^[0-9a-f-]{6,36}$/i.test(positional[0]))) return ['claim', ...args];
281
+ return ['new', ...args];
282
+ }
283
+
242
284
  module.exports = async function run() {
243
- const args = process.argv.slice(3);
285
+ let args = process.argv.slice(3);
286
+ if (process.argv[2] === 'dispatch') args = dispatchToTaskArgs(args);
244
287
  const sub = args[0] || 'list';
245
288
  const viaIdx = args.indexOf('--via');
246
289
  const via = viaIdx !== -1 ? args[viaIdx + 1] : null;
@@ -251,9 +294,13 @@ module.exports = async function run() {
251
294
  if (sub === 'list') return await listTasks(config);
252
295
  if (sub === 'new') return await newTask(config, rest.join(' ').trim());
253
296
  if (sub === 'claim') return await claimTask(config, rest[0], via);
254
- console.log(`\n Usage: phewsh task [list | new "<title>" | claim <id> [--via <harness>]]\n`);
297
+ if (sub === 'invite') return await inviteTeammate(config, rest[0]);
298
+ if (sub === 'join') return await joinProjects(config);
299
+ console.log(`\n Usage: phewsh task [list | new "<title>" | claim <id> [--via <harness>] | invite <email> | join]\n phewsh dispatch ["<title>" | <id> | next] [--via <harness>]\n`);
255
300
  } catch (err) {
256
301
  console.error(`\n ${red('✗')} ${err.message}\n`);
257
302
  process.exitCode = 1;
258
303
  }
259
304
  };
305
+
306
+ module.exports.dispatchToTaskArgs = dispatchToTaskArgs;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "phewsh",
3
- "version": "0.15.68",
3
+ "version": "0.15.70",
4
4
  "description": "Turn intent into action. Structure your thinking, execute your next step.",
5
5
  "bin": {
6
6
  "phewsh": "bin/phewsh.js"